Two same types (mapped type of generic param) are not assignable to each other
Bug Report
🔎 Search Terms
Keywords: generic function, mapped types
Errors:
- Type 'T1' is not assignable to type 'T2'.
- Two different types with this name exist, but they are unrelated.
I got both error messages in my original code, but only the first error message is left in the minimal reproduce.
🕗 Version & Regression Information
4.7.2
All other versions also have this issue.
⏯ Playground Link
https://www.typescriptlang.org/play?#code/C4TwDgpgBAYgjFAvFAPAFQHwAoCGAnAcwC4o0BKJDKAJTnQwG4AoUSGuzJKAbyaigDaAaSgBLAHZQA1hBAB7AGakoOAM5QA5MAirgGqBAAe28QBN1IgPxRxEAG4Q8UEkIC6JAAzMAvsyYB6fwNDHABjYAAbEChgAAtoVRwAW2hWCBZwaBgAJi56XEISckoabPpmNNL6Ll5+YTFJGXklNBV1LR09YJNzKCsbe0dnPvcoLyZfJiZTCFCI-GgIiGAoOzgSeGYZuYWoJZW7bI3svzWuQ4YoQKgAUTw8OTwmQ-O4S+u7h6emIA
💻 Code
type F1 = <T>(arg: T) => R1<T>;
type R1<T> = {
[K in keyof T as 'test' extends K ? never : K]: 0;
};
// exactly the same type
type F2 = <T>(arg: T) => R2<T>;
type R2<T> = {
[K in keyof T as 'test' extends K ? never : K]: 0;
};
declare let v1: F1;
declare let v2: F2;
v1 = v2; // Error
v2 = v1; // Error
The problem appears when a conditional type is used in a key remapping of mapped types.
🙁 Actual behavior
The two same types are not assignable to each other.
🙂 Expected behavior
The two same types should be assignable to each other. Because they are written in the same way.
In my case, the two "same-written type declarations" exist because they come from the same package with two different versions.
Maybe related to https://github.com/microsoft/TypeScript/issues/48626#issuecomment-1098168620? I don't fully understand the comment.
The issue here is that we only consider two mapped types with as clauses related if the as clause types are identical. We could probably be a bit more flexible here. Meanwhile, the workaround is to use a shared as type:
type N<K> = 'test' extends K ? never : K;
type F1 = <T>(arg: T) => R1<T>;
type R1<T> = {
[K in keyof T as N<K>]: 0;
};
type F2 = <T>(arg: T) => R2<T>;
type R2<T> = {
[K in keyof T as N<K>]: 0;
};
I am running into the same issue and found a slightly simpler example. Link to playground.
type R1 = <T extends PropertyKey>() => {
[K in T as K extends unknown ? K : K]: 0
}
type R2 = <T extends PropertyKey>() => {
[K in T as K extends unknown ? K : K]: 0
}
declare let v1: R1;
declare let v2: R2;
v1 = v2; // Error
v2 = v1; // Error
Type 'R2' is not assignable to type 'R1'.
Type '{ [K in T as K extends unknown ? K : K]: 0; }' is not assignable to type '{ [K in T as K extends unknown ? K : K]: 0; }'.
Two different types with this name exist, but they are unrelated.
Removing as K extends unknown ? K : K (even though this clause is a noop) unexpectedly removes that error.
Unfortunately, in my case, the workaround described by @ahejlsberg is not possible because R1 and R2 are actually two instances of the same package installed in different places in node_modules. This leads to my package's types not being assignable with themselves (or more precisely, a copy of themselves).