I have following TypeScript code:
type Test = {
a: string;
b: boolean;
c: number;
}
const instance: Test = {
a: 'a',
b: true,
c: 2,
}
function getValue<T extends keyof Test>(val: T): Test[T] {
return instance[val];
}
function setValue<T extends keyof Test>(key: T, value: Test[T]): void {
instance[key] = value;
onChangeValue(key, value);
}
function onChangeValue<T extends keyof Test>(key: T, value: Test[T]): void {
switch (key) {
case 'a':
let a: string = value; // why TS won't infer that value must be type Test['a'] ie. string? Is there any way to fix it?
break;
case 'b':
let b: boolean = value;
break;
case 'c':
let c: number = value;
break
}
}
let d: number = getValue('c'); // works fine
setValue('a', 'fsdfdsf'); // works fine
So basically I have methods which accept one argument which is key in object(type) and second is value to set value of that key in object. I'm using here lookup types based on value of passed key. It is working fine for usage of method which returns value based on key, and sets value based on key. However I have third function onChangeValue
inside of which I want to recognize type of value parameter based on type of key parameter. Why it doesn't work here? Why compiler won't correctly infer type of value parameter? Is there any way to fix it and make it work without explicit type casting?
As @jcalz pointed out in their comment, the type of onChangeValue
doesn't mean that the type of value
is a specific type.
For example, when you declare a constant k
like this, its type becomes 'a' | 'b'
.
const k: 'a' | 'b' = true ? 'a' : 'b' as const
Then when you call onChangeValue
with k
, onChangeValue
will be instantiated as function onChangeValue<'a' | 'b'>(key: 'a' | 'b', value: string | boolean): void
.
onChangeValue(k, true);
As you can see, even though key
is 'a'
, value
can be boolean
. That's why the compiler doesn't narrow the type of value
in the switch
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With