Typescript matcha funktionsargument till nyckel och värde i en typkarta
Jag har ett väldigt enkelt fall, men min erfarenhet av Typescript-typning är begränsad och jag verkar inte kunna lösa detta till synes enkla fall.
Jag har en typkarta till exempel som denna:
interface KeyValueMap {
key: 'value';
foo: 'bar';
}
Nu skulle jag vilja skriva det första och andra argumentet av en funktion till nyckeln och värdet av ovanstående karta
const test = <K extends keyof KeyValueMap>(key: K, value: KeyValueMap[K]) => {
switch (key) {
case 'key':
return value; // currently getting "KeyValueMap[K]" expecting "value"
case 'foo':
return value; // currently getting "KeyValueMap[K]" expecting "bar"
}
};
Jag försökte söka efter ett liknande fall, men det verkar som att min Google är trasig... Så jag tar inte illa upp om det markeras som en duplicat om ett sådant exempel redan finns på Stackoverflow.
UPPDATERA
Efter kommentaren från @ShivamSingla under min fråga inser jag att jag kanske inte var tillräckligt tydlig i min fråga. Jag är inte intresserad av funktionsreturvärdena, men vill redan att typen ska kännas igen i själva funktionslogiken (inom switch-case). Jag kommer att ändra exemplet för att göra det tydligare:
interface KeyObjectMap {
foo: {
key1: 'value1';
};
bar: {
key2: 'value2';
};
}
const test = <K extends keyof KeyObjectMap>(key: K, value: KeyObjectMap[K]) => {
switch (key) {
case 'foo':
return value.key1; // property 'key1' does not exist on 'KeyObjectMap[K]'
case 'bar':
return value.key2; // property 'key2' does not exist on 'KeyObjectMap[K]'
}
};
Här kan du hitta en lekplats med detta exempel
Svar #1
Eftersom key och value inte är associerade, kan value tilldelas på nytt innan switch-satsen. Det är därför felet uppstår. Se detta svar för bättre förståelse.
interface KeyObjectMap {
foo: {
key1: 'value1';
};
bar: {
key2: 'value2';
};
}
type K1 = keyof KeyObjectMap
const test = <K extends K1 = K1>(key: K, value: KeyObjectMap[K]) => {
// error here, 'key2' is missing
value = {
key1: 'value1',
}
// value is actually intersection, subtype `KeyObjectMap` actually
value = {
key1: 'value1',
key2: 'value2',
}
// since `key` and `value` are not associated, value can be re-assigned
// before switch case. That's why the error
switch (key) {
case 'foo':
return value.key1; // property 'key1' does not exist on 'KeyObjectMap[K]'
case 'bar':
return value.key2; // property 'key2' does not exist on 'KeyObjectMap[K]'
}
};
Lekplats
Möjlig lösning
interface KeyObjectMap {
foo: {
key1: 'value1';
};
bar: {
key2: 'value2';
};
}
const test = <O extends Partial<KeyObjectMap>>(obj: O) => {
if (obj.foo) {
return obj.foo.key1
}
if (obj.bar) {
return obj.bar.key2
}
return undefined
};
// calling
const c = test({foo: {key1: 'value1'}})
Lekplats
