Skip to content

Generic type inference prefers conditional types #31766

Closed

Description

@bowenni

TypeScript Version: 3.4.5 and 3.5.1

Search Terms: Conditional types, Type inference

Code

interface I {a: string}
type Cond<T> = T extends any ? Partial<T>: T;

declare function f<T>(x1: T, x2: Cond<T>): T;
function g(p1: I, p2: Cond<I>): I {
  return f(p1, p2); // error here
}

Expected behavior:
No errors. A trivial type inference is T=I. This is also the behavior of TypeScript 3.3.

Actual behavior:
error TS2322: Type 'Partial<I>' is not assignable to type 'I'.
From that error message the actual inference is T=Partial<I> (or Cond<I>), which seems like a regression to me.

Playground Link:
playground link

Related Issues:
There are some issues around conditional types but nothing quite a duplication, I think.
#31601 requires function overloads
#24085 is a problem with enums
#30489 is more about type inference on the conditional type itself, not the generic type when the conditional type is used
#30341 is similar but it's marked as fixed

Rado Kirov (@rkirov)

Activity

  1. RyanCavanaugh commented on Jun 13, 2019

    @RyanCavanaugh
    Member

    What is the intent of writing T extends any ?

  2. bowenni commented on Jun 13, 2019

    @bowenni
    Author

    What is the intent of writing T extends any ?

    To create a conditional type. I think the problem only happens with a conditional type.

    If the example is oversimplified and doesn't make sense, below is another example, without the T extends any.

    interface I { a: string }
    type DeepPartial<T> =
        T extends object ? {[K in keyof T]?: DeepPartial<T[K]>} : T;
    
    declare function f<T>(t: T, partial: DeepPartial<T>): T;
    function g(p1: I, p2: Partial<I>): I {
      return f(p1, p2); // error Type 'Partial<I>' is not assignable to type 'I'.
    }
  3. RyanCavanaugh commented on Jun 25, 2019

    @RyanCavanaugh
    Member
    interface I { a: string }
    type DeepPartial<T> =
        T extends object ? {[K in keyof T]?: DeepPartial<T[K]>} : T;
    
    declare function f<T>(t: T, partial: DeepPartial<T>): T;
    function g(p1: I, p2: Partial<I>): I {
        // T inferred to be Partial<I>; should be I
      return f(p1, p2); // error Type 'Partial<I>' is not assignable to type 'I'.
    }
  4. ahejlsberg commented on Jul 1, 2019

    @ahejlsberg
    Member

    This is caused by #30010. Part of why we inferred to a union type was to get lower priority candidates for inferences to naked type variables, but that got lost with the fix in #30010. We just need to reinstate that part.

  5. weswigham commented on Jul 2, 2019

    @weswigham
    Member

    This is caused by #30010.

    To be fair, at the time I'm pretty sure we had done away with the naked type variable priority; we just didn't think to add it to the conditional inference bit when we added it back. :P

  6. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions