TypeScript - Hur man representerar en indexsignatur som en generisk typ


Indexsignaturer i TypeScript definieras så här:

Ordbok

[key: string]: T

Matris

[index: number]: T

Dessa skulle kunna paketeras i några enkla, återanvändbara typer:

type DictionaryIndex<T> = {
    [key: string]: T
}

type ArrayIndex<T> = {
    [index: number]: T
}

Nu vill jag omsluta dessa i en enda typ. Jag försökte detta:

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

Detta kompileras inte på grund av följande fel:

En indexsignaturparameter måste vara av typen 'string' eller 'number'.

Är detta inte möjligt?

Vad i helvete för?

För att

foo(obj: Index<string, Bar>)
foo(obj: Index<string, Bar> & Fooable<string>)

ser prydligare ut än

foo(obj: { [key: string]: Bar })
foo(obj: { [key: string]: Bar, canFoo: (foo: string) => Bar })

Svar #1

cool fråga!
Jag tror att anledningen är att detta verkligen är ett kantfall för kompilatorn som antagligen inte har implementerats eftersom det inte är värt ansträngningen.

indexegenskapsnycklar kan bara vara nummer, det är uppenbart, och objektets egenskapsnycklar kan bara vara strängar eller nummer. Så i slutändan anger din begränsning bara vad som redan är ett faktum och vad som skulle behöva hanteras av kompilatorn via ett specialfall.
Så igen, jag antar att Saint Anders övergav det försöket ;-)

men varför inte göra detta

type StrIndex<TValue> = {
    [key: string]: TValue
}

type NumIndex<TValue> = {
    [key: number]: TValue
}

foo(obj: StrIndex<Bar>)
foo(obj: StrIndex<Bar> & Fooable<string>)

Det är inte lika snyggt som din lösning, men som en kompromiss verkar det okej, särskilt eftersom mängden av XXXIndex-typer är begränsad till 2

Svar #2

Ett alternativt lösning är att använda Record-verktyget.

foo(obj: Record<string, Bar>)

https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type

Relaterade artiklar