TypeScript Version: 3.2.1
Search Terms:
keyof, Record, Partial, ...
But actually, I don't know how to exactly express this problem in the search box...
Code
// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
interface ITest {
a: string;
}
type PartialRecord<K extends keyof any, T> = {
[k in K]?: T;
};
class SlotTest<ES> {
private _slots1: Partial<Record<keyof ES, ITest>> = {};
private _slots2: Record<keyof ES, ITest> = {} as any;
private _slots3: PartialRecord<keyof ES, ITest> = {};
public doTest1<K extends keyof ES>(name: K): void {
/**
* It works well in v2.9.x, but fails in v3.2.1.
* [ts] Type '{ a: string; }' is not assignable to type 'Record<keyof ES, ITest>[K]'. [2322]
*/
this._slots1[name] = {"a": "ggg"};
}
public doTest2<K extends keyof ES>(name: K): void {
/**
* This works fine.
*/
this._slots2[name] = {"a": "ggg"};
}
public doTest3<K extends keyof ES>(name: K): void {
/**
* This works fine.
*/
this._slots3[name] = {"a": "ggg"};
}
}
Expected behavior:
When I used v2.9.2, the code works well.
Actual behavior:
But, when I upgrade to v3.2.1, it fails with compilation error message like this:
Type '{ "a": string; }' is not assignable to type 'Record<keyof ES, ITest>[K]'.
Playground Link:
Related Issues:
This seems reasonable; assigning any concrete value to a generic is almost certainly incorrect. @weswigham any reason you believe this is a bug?
Oh, I see, the property types aren't generic.
@DanielRosenwasser Yes. What makes me confused is that PartialRecord<K, V> is okay but Partial<Record<K, V>> does not.
A simplified repro:
function foo<T, K extends keyof T>() {
let x: Partial<Record<keyof T, string>>[K] = "hello"; // Error, but should be ok
}
So, the reason it worked with 2.9.x is that we had some serious holes in checking of assignments to indexed access types--we'd permit assignments of pretty much anything. We are now being more thorough, which is uncovering other design limitations. In this particular case, the limitation is that we do not simplify indexed accesses applied to mapped types beyond one level because it could cause infinite recursion when mapped types circularly reference themselves. However, I think we have a fairly compelling example here of why we ought to simplify at least a few levels deep.
Can you please reopen this issue?
I have the following two level mapped types
function f<K extends string, V, T extends Partial<Record<K, V[]>>>(
object: T,
key: K,
value: V[],
) {
object[key] = value;
}
Expected behavior:
No errors.
Actual behavior:
index.ts:6:3 - error TS2322: Type 'V[]' is not assignable to type 'T[K]'.
TypeScript Version: 3.4.0-dev.20190130
I think my repro is a duplicate of this issue, but happy to file a separate bug if you find these two different.
Most helpful comment
A simplified repro:
So, the reason it worked with 2.9.x is that we had some serious holes in checking of assignments to indexed access types--we'd permit assignments of pretty much anything. We are now being more thorough, which is uncovering other design limitations. In this particular case, the limitation is that we do not simplify indexed accesses applied to mapped types beyond one level because it could cause infinite recursion when mapped types circularly reference themselves. However, I think we have a fairly compelling example here of why we ought to simplify at least a few levels deep.