Typescript-arraygränssnitt med numrerat index och anpassade egenskaper åtkomliga via strängnycklar


Jag skulle vilja ha en matris av objekt indexerade med siffror och också lägga alla objekt i matrisen under en specifik nyckel

Något sådant här:

const myArray:ICustomArray = []
myArray.push(item)
myArray[item.key] = item;

Men jag har svårt att definiera dess gränssnitt. Först förväntade jag mig att något sådant här skulle fungera, men det gör det inte.

export interface ICustomArray extends Array<IItem> {
  [index: number] : IItem;
  [key: string] : IItem;

}

Svar #1

Problemet med din typ är att den är inkonsekvent när det gäller strängindexsignaturen ([key: string] : IItem;). Inte alla nycklar som nås på detta sätt kommer att vara av typen IItem om du ärver en array. Till exempel kommer myArray['map'] att vara array-funktionen och inte IItem. Detta är anledningen till att TypeScript tvingar strängindexsignaturen att vara kompatibel med ALLA statiskt deklarerade medlemmar av gränssnittet.

Det finns dock en kryphål i denna kontroll. Kryphålet med intersection-typen. Vi kan deklarera ICustomArray som en intersection av array och en typ som har indexsignaturen.

export type ICustomArray = Array<IItem> & {
  [key: string] : IItem;
}

let item: IItem;
const myArray: ICustomArray = [] as ICustomArray
myArray.push(item)
myArray[item.key] = item;

Detta kommer mestadels att fungera på det sätt du skulle förvänta dig:

let o = myArray['map'] // o is a function of type  <U>(callbackfn: (value: IItem, index: number, array: IItem[]) => U, thisArg?: any) => U[]
let i = myArray['key'] //IItem
declare let randomStr: string
let d = myArray[randomStr] //IItem .. but if randomStr= map, we have a runtime problem

Svar #2

Det du gör är konstigt och Typescript-teamet stöder medvetet inte sådana konstiga idéer. Därför måste du göra några konstiga lösningar (förlåt för att jag skrev "konstig" 3 gånger):

interface IItem {
    key: string
}

type ICustomArray = Array<IItem> & {
    [key: string]: IItem
}

const myArray: ICustomArray = [] as unknown as ICustomArray

myArray.push(item)
myArray[item.key] = item;

Konstigheten ligger i att kombinera array och objekt. Dessutom kan objektet ha vilken nyckel som helst. Det finns inte mycket nytta med ett gränssnitt med godtyckliga nycklar.