Jak mohu specifikovat, že generický typ T[K] v TypeScriptu je typu number?
Mám jednoduchou funkci v Typescriptu, která vypadá takto:
function getProperty<T, K extends keyof T>(obj: T, key: K): number {
return obj[key]; // This line is not compiling.
// Typescript will yell: "Type 'T[K]' is not assignable to type 'number'."
}
Moje použití vypadá takto:
const someObj = {
myValue: 123,
otherProperty: '321'
}
getProperty(someObj, 'myValue')
Nevím, jaká bude struktura someObj.
Má otázka je: Jak mohu staticky specifikovat, že T[K] je typu číslo?
Odpověď č. 1
Pokud jsou objekty, se kterými pracujete, dostatečně typované na to, aby jejich tvar byl Typescriptem znám, můžete to úplně udělat [odkaz na playground TypeScriptu, pokud chcete trochu experimentovat].
Stačí zúžit, které identifikátory key mohou být na jednu z těch, které odkazují na vlastnost typu number:
const someObj = {
myValue: 123,
otherProperty: '321'
};
getProperty(someObj, 'myValue'); // works
getProperty(someObj, 'otherProperty'); // wails
function getProperty<T, K extends NumericProps<T>>(obj: T, key: K): number {
return obj[key];
}
type NumericProps<T> = {
[K in keyof T]: T[K] extends number ? K : never
}[keyof T];
Odpověď č. 2
Nevím, jaká bude struktura
someObj.
Pak vám TypeScript s tímto opravdu nemůže pomoci. Kontrola typů v TypeScriptu probíhá během kompilace. Pokud bude struktura someObj známa až během běhu programu, TypeScript nemůže zajistit typovou bezpečnost přístupu k této struktuře. Museli byste vědět, jaké klíče vlastností a možné hodnoty pro tyto vlastnosti existují během kompilace.
Například: Ve vašem příkladu jsou názvy vlastností řetězce a hodnoty vlastností jsou buď řetězce nebo čísla (ale ne booleany nebo objekty atd.). Můžete deklarovat typ indexovaný řetězci (protože všechny názvy vlastností jsou nakonec řetězce nebo Symboly, v tomto případě řetězce), kde hodnoty vlastností jsou čísla nebo řetězce:
declare type SomeObjType = {
[key: string]: number | string
};
a pak getProperty je:
function getProperty<T extends SomeObjType>(obj: T, key: string): number | string {
return obj[key];
}
a můžete to použít takto (v tomto případě používám JSON.parse, abych simuloval příjem těchto dat zvenčí programu):
const someObj: SomeObjType = JSON.parse(`{
"myValue": 123,
"otherProperty": "321"
}`);
console.log(getProperty(someObj, 'myValue'));
console.log(getProperty(someObj, 'otherProperty'));
Na hřišti
Ale to vám mnoho nepomůže a uzavírá možnost, že hodnoty vlastností jsou něco jiného než čísla nebo řetězce.
Možná budete muset jednoduše použít object:
function getProperty(obj: object, key: string) {
return obj[key];
}
const someObj = JSON.parse(`{
"myValue": 123,
"otherProperty": "321"
}`);
console.log(getProperty(someObj, 'myValue'));
console.log(getProperty(someObj, 'otherProperty'));
Na hřišti
