The compiler is unable to verify this scenario for you, but you can use a type assertion as a workaround:
class Class<T> {
f<K extends keyof T>(k: K, v: T[K]) {
const badPartial: Partial<T> = { [k]: v }; // error!
const goodPartial: Partial<T> = { [k]: v } as Pick<T, K> & Partial<T>; // okay
}
}
This is one solution to the issue at hand. The compiler faces two main obstacles in dealing with cases like these.
The first challenge arises when the key of a computed property is not statically known or unique:
const k1 = "a";
const o1 = { [k1]: 123 };
// const o1: {[k1]: number};
o1.a; // okay
o1.b; // error
If the key type is generic or a union of string literals, TypeScript widens it to string
, resulting in unexpected behavior:
const k2 = Math.random() < 0.5 ? "a" : "z";
const o2 = { [k2]: 123 };
// const o2: {[x: string]:number};
o2.a; // no error, might not exist
o2.b; // no error, definitely doesn't exist
function foo<K extends string>(k3: K) {
const o3 = { [k3]: 123 };
// const o3: {[x: string]:number};
o3.a; // no error, probably doesn't exist
}
Another stumbling block relates to associative types and higher-order type manipulation, where the compiler struggles to infer compatibility between various types. This leads to the need for manual intervention through type assertions. For more details on this aspect, refer to the open issuehere.
Due to these limitations in TypeScript's inference capabilities, relying solely on the compiler to verify certain assignments feasibly may not yield desirable outcomes. Hence, utilizing type assertions remains a practical approach to address such scenarios effectively.
Hopefully, the provided insights will prove valuable. Best of luck!
Playground link to code