TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

`T` is not assignable to `SomeType | Exclude<T, SomeType>` where `T` is a generic union type

Open 12joan opened this issue 10 months ago • 1 comments

🔎 Search Terms

"exclude generic"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about generics and Exclude

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.9.0-dev.20250319#code/C4TwDgpgBAsiAq5oF4oHIAeaoB90jQG4AoYgMwFcA7AY2AEsB7KqMgHnigg2AioBMAzrARIAfAAoMALijwAlLMzY8AUQw0ANhX4QOAGnRYxUAN7EoUAE4RgFKywwkAvkA

💻 Code

type MyType = 'x' | 'y';

function f<T extends MyType>(x: T): 'x' | Exclude<T, 'x'> {
  return x;
}

🙁 Actual behavior

TypeScript doesn't treat T and SomeType | Exclude<T, SomeType> as equivalent where T is a generic.

In the above snippet, return x has a type error:

Type 'T' is not assignable to type '"x" | Exclude<T, "x">'.
  Type 'MyType' is not assignable to type '"x" | Exclude<T, "x">'.
    Type '"y"' is not assignable to type '"x" | Exclude<T, "x">'.

If I remove the generic and write instead type T = MyType, then the code has no errors.

🙂 Expected behavior

As far as I'm aware, there are no values that are assignable to T but not to SomeType | Exclude<T, SomeType>, where T is a union type.

Proof:

The docs for Exclude seem to suggest that a type X is assignable to Exclude<T, SomeType> (where T is a union type) if and only if X is assignable to T AND X is not assignable to SomeType. Therefore, T is assignable to Exclude<T, SomeType> if and only if T is assignable to T (trivially true) AND T is not assignable to SomeType.

There are two cases:

  1. If T is assignable to SomeType, then T is assignable to SomeType | Exclude<T, SomeType>.
  2. If T is not assignable to SomeType, then T is assignable to Exclude<T, SomeType> as above. Therefore, T is assignable to SomeType | Exclude<T, SomeType>.

Therefore, T should always be assignable to SomeType | Exclude<T, SomeType>.

As such, TypeScript's assertion that Type 'T' is not assignable to type '"x" | Exclude<T, "x">' seems to be mistaken, and I would expect the above snippet to compile without errors.

Additional information about the issue

No response

12joan avatar Mar 19 '25 10:03 12joan

This is a design limitation. Resolving of conditional types involving generic type arguments is deferred. (Basically, the compiler doesn't know what type T actually is, so it can't figure out what type Exclude<T, ...> is either.)

This would require #33912 (not sure if your case is covered by this).

MartinJohns avatar Mar 19 '25 11:03 MartinJohns

This issue has been marked as "Design Limitation" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

typescript-bot avatar Mar 30 '25 01:03 typescript-bot