Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript type inference with lookup types and switch case

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?

like image 244
Furman Avatar asked Oct 16 '25 23:10

Furman


1 Answers

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.

like image 176
snak Avatar answered Oct 18 '25 16:10

snak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!