Hvordan kan man begrense en TypeScript-generisk til å være en indekserer?


I TypeScript kan du indeksere inn i et objekt ved å bruke kun en string, number eller symbol.

Jeg vil ha en generisk som tillater at de generiske parameterne brukes som indekser.

function foo<T extends number|string>(a: T): void {
    let x: any = {};
    x[a] = 42; // Error: an index expression argument must be of type...
}

Hvis jeg kaster til en number|string, kompilerer det:

function foo<T extends number|string>(a: T): void {
    let x: any = {};
    let i: number|string = a;
    x[i] = 42; // OK
}

Så typekontrollen er smart nok til å vite at hvis T utvider number|string, så kan jeg tilordne det til en number|string (som jeg deretter kan bruke til å indeksere i et objekt), men av en eller annen grunn lar den meg ikke indeksere direkte med en T.

Finnes det en måte å spesifisere i den generiske begrensningen at typen som sendes inn kan brukes som en indekserer?

Merk: Jeg bruker en generisk type og ikke number|string direkte fordi jeg vil begrense den generiske typen til å bare akseptere verdier fra et spesifikt enum eller en string literal union.

Rediger: Et mer overbevisende eksempel (og nærmere det jeg egentlig prøver å gjøre), er dette:

// The following line fails to compile even though Key is number | string
type Dictionary<Key extends number | string, Value> = { [index: Key]: Value }; 

// Had it compiled I would expect the following behaviour
type Answer = "yes" | "no" | "maybe";
let grades = {} as Dictionary<Answer, number>;  

grades["yes"] = 10;
grades["nope"] = 5; // Should be an error "nope" is not assignable to Answer

Svar #1

// The following line fails to compile even though Key is number | string
type Dictionary<Key extends number | string, Value> = { [index: Key]: Value };

Bruk in-nøkkelordet:

type Dictionary<TKey extends number | string, TValue> = {
  [key in TKey]: TValue
};

Relaterte artikler