Microsoft/TypeScript

Regression: Generic function returning union of tuples is not assignable to identical type since v4.2

Open

#63019 opened on Jan 20, 2026

View on GitHub
 (4 comments) (0 reactions) (0 assignees)TypeScript (48,455 stars) (6,726 forks)batch import
Domain: check: Type InferenceHelp WantedPossible Improvement

Description

🔎 Search Terms

generic function assignability, union return type, tuple union, TS2322, regression v4.2, generic type alias

🕗 Version & Regression Information

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/C4TwDgpgBAShCGATAglAvFAPDAfACgEp0coBtAM3gBsBnCAGlgF0oAfM4AJwFcHY2o3AHaII5AJZCIiJgG4AsAChQkWAkQAhdFlyFiZSrT4wW7Ul16MYA4aIlSZCxUoD0LqAFFOnAPacAXFAAKuDQAORwSMhhUOI0UEI+wFDwNDTiAOZC8ABGVNDAPlAq4ZGaYQB0SgDGPkI0ycAQDdp4APqBZcgEnepaaCRtTq7uyLRFABbwYJD1UADu4sATUD45AFYQ1Y2hNEolakgA8huoGNj4RANQAN5QiHUQgYZ0slAAbtS8nVAAvgJ3B5SQIWCBvT5Ub78di2MSSaR-JwHMondb9HSXfSAx7PaivD5fJ78f7sbHA4o8MEEyFE6wwkRwhyIpQjTzePyBEKqCLqVHRWLxRLJVLpLK5fLFIoHHnHDYaSo1OotJoNVGtDqHRB8nqa1H9QayIA

💻 Code

type ReadA = <R>() => [false, R] | [true, R | undefined];
type ReadB = <R>() => [false, R] | [true, R | undefined];

// Error: Type 'ReadA' is not assignable to type 'ReadB'.
const test = (_: ReadA): ReadB => _;

// Also happens with object types
type ReadObjA = <R>() => { done: false; value: R } | { done: true; value: R | undefined };
type ReadObjB = <R>() => { done: false; value: R } | { done: true; value: R | undefined };

// Error: Type 'ReadObjA' is not assignable to type 'ReadObjB'.
const testObj = (_: ReadObjA): ReadObjB => _;

🙁 Actual behavior

The code fails to compile with error TS2322: Type 'ReadA' is not assignable to type 'ReadB'.

It appears that the compiler incorrectly widens the generic type parameter R in the source type. Although ReadA is defined as [false, R] | ..., the error message reports the source type as having [false, R | undefined].

It seems that during the generic signature assignability check, the undefined from the [true, R | undefined] branch is leaking into the inference of R for the entire union, causing the false branch to become [false, R | undefined]. This widened source type is then incompatible with the target's more strict [false, R] branch.

Type 'ReadA' is not assignable to type 'ReadB'.
  Type '[true, R | undefined] | [false, R | undefined]' is not assignable to type '[false, R] | [true, R | undefined]'.
    Type '[false, R | undefined]' is not assignable to type '[false, R] | [true, R | undefined]'.
      Type '[false, R | undefined]' is not assignable to type '[false, R]'.
        Type at position 1 in source is not compatible with type at position 1 in target.
          Type 'R | undefined' is not assignable to type 'R'.
            'R' could be instantiated with an arbitrary type which could be unrelated to 'R | undefined'.(2322)
Type 'ReadObjA' is not assignable to type 'ReadObjB'.
  Type '{ done: false; value: R | undefined; } | { done: true; value: R | undefined; }' is not assignable to type '{ done: false; value: R; } | { done: true; value: R | undefined; }'.
    Type '{ done: false; value: R | undefined; }' is not assignable to type '{ done: false; value: R; } | { done: true; value: R | undefined; }'.
      Type '{ done: false; value: R | undefined; }' is not assignable to type '{ done: false; value: R; }'.
        Types of property 'value' are incompatible.
          Type 'R | undefined' is not assignable to type 'R'.
            'R' could be instantiated with an arbitrary type which could be unrelated to 'R | undefined'.(2322)

🙂 Expected behavior

The code should compile without errors because ReadA and ReadB are structurally identical types.

Additional information about the issue

No response

Contributor guide