I have a generic function that reads or writes the caller-chosen property of a given object. I'm using type constraints to ensure that the key passed is for a property that is assignable to or from the relevant type. Calling code appears to typecheck correctly. The usage of the object's property within the implementation does not typecheck as expected.
In this example I use boolean as the expected type. I've commented the lines that are not typechecking as expected. You can also see this example in the typescript playground here.
How can I express the signature of booleanAssignmentTest so that the typechecker understands obj[key] has type boolean? Can it be done in a fashion that keeps the boolean itself generic to allow multiple such similar functions, that work with other types, to be defined uniformly?
type KeysOfPropertiesWithType<T, U> = {
// We check extends in both directions to ensure assignment could be in either direction.
[K in keyof T]: T[K] extends U ? (U extends T[K] ? K : never) : never;
}[keyof T];
type PickPropertiesWithType<T, U> = Pick<T, KeysOfPropertiesWithType<T, U>>;
function booleanAssignmentTest<T extends PickPropertiesWithType<T, boolean>, K extends KeysOfPropertiesWithType<T, boolean>>(obj: T, key: K): void {
let foo: boolean = obj[key]; // Fine!
let foo2: string = obj[key]; // No error, but there should be!
obj[key] = true; // Error: "Type 'true' is not assignable to type 'T[K]'."
}
let foo = { aBool: false, aNumber: 33, anotherBool: false };
booleanAssignmentTest(foo, "aBool"); // Fine!
booleanAssignmentTest(foo, "anotherBool"); // Fine!
booleanAssignmentTest(foo, "aNumber"); // Error: working as intended!
I'm using tsc Version 3.4.5 in case it's relevant.
Update:
I found the following answer on a similar issue: https://stackoverflow.com/a/52047487/740958
I tried to apply their approach which is simpler and works a little better, however the obj[key] = true; statement still has the same issue.
function booleanAssignmentTest2<T extends Record<K, boolean>, K extends keyof T>(obj: T, key: K): void {
let foo: boolean = obj[key]; // Fine!
let foo2: string = obj[key]; // Error: working as intended!
obj[key] = true; // Error: "Type 'true' is not assignable to type 'T[K]'."
}
let foo = { aBool: false, aNumber: 33, anotherBool: false };
booleanAssignmentTest2(foo, "aBool"); // Fine!
booleanAssignmentTest2(foo, "anotherBool"); // Fine!
booleanAssignmentTest2(foo, "aNumber"); // Error: working as intended!
This ^^ example on TS Playground.
from Assignment involving generic property of generic object fails to typecheck correctly within generic function
No comments:
Post a Comment