Vyhledávání na webu

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

Související články