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
};
