Typescript array interace with numbered index and custom properties accessbile by string keys

typescript interface array
typescript interface constructor
typescript index signature
typescript interface inheritance
typescript export interface
typescript interface default value
typescript interface naming convention
typescript array of objects

I would like to have array of objects indexed by numbers and and also to put all of the objects on the array under specific key

Something like this:

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

But I am struggling to define its interface. First I expected something like this will work but it does not.

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

}


What you are doing is weird and Typescript team intentionally does not support such weird ideas. Hence, you have to do some weird workarounds (sorry for writing "weird" 3 times):

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;

The weirdness is in combining array and object. Moreover, the object can have any keys. There is no much benefit from an interface with arbitrary keys.

TypeScript - Using Interfaces to describe Indexable Types, TypeScript only allows two types for indexes (the keys): string and number. indexable (arrays created with [] are also objects accessible via (i.e. indexer of number type) we can define array properties/methods which need  In TypeScript, arrays are themselves a data type, just like number and string). TypeScript provides quite a lot of ways for you to declare an array…but all of the methods give you the same result. For example, you can declare an array using a "square bracket syntax" that will look very familiar to JavaScript developers.


The problem with your type is that it is inconsistent with regard to the string index signature ([key: string] : IItem;). Not all keys accessed this way will be of type IItem if you inherit array. For example myArray['map'] will be the array function not IItem. This is the reason typescript forces the string index signature to be compatible with ALL statically declared members of the interface.

There is a loophole in this check though. The intersection type loophole. We can declare ICustomArray as an intersection of array and a type that has the index signature.

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

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

This will mostly have work the way you would expect:

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

Exploiting TypeScript Arrays -- Visual Studio Magazine, In TypeScript, arrays are themselves a data type, just like number and string). and properties that you'd expect from a JavaScript array: length, pop, push, of the array in the interface, you can selectively provide access to the You can, for example, use negative values and strings as your array index for  Like previous post on Function type interface, we can also use interfaces to describe Array types. Look at below code snippet. In the 1 st part of the code snippet, we have declared NameArray that stores string and in the 2 nd part of the code snippet, we have AgeArray that returns number.


I have been thinking a bit about the infamous TypeScript Dictarray, as this has come up a few times.

There is a quick and dirty fix that basically supresses the error on type creation. The reason this is interesting is that the type checking and inference both work as expected if you do this. You are effectively ignoring the conflice between all of the members of Array with your string-keyed items.

interface Dictarray extends Array<string> {
    [index: number]: string;
    // @ts-ignore: I'm creating a Dictarray!
    [key: string] : string;
}

If you use this, you can effectively carry on exactly as you anticipated when you create the type - although if you are creating a new type, you could consider not jamming them together as an option.

You can use this generic Dictarray rather than a hard-stringed version:

interface Dictarray<T> extends Array<T> {
    [index: number]: T;
    // @ts-ignore: I'm creating a Dictarray!
    [key: string]: T;
}

const dictarray = [] as Dictarray<string>;

Our First Interface, It still represents having a single property called label that is of type string . interface StringArray { [index: number]: string; } let myArray: StringArray; myArray Within the Control class it is possible to access the state private member through  Joins all elements of an array into a string. 7. lastIndexOf() Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. 8. map() Creates a new array with the results of calling a provided function on every element in this array. 9. pop()


Advanced Types · TypeScript, Optional parameters and properties; Type guards and type assertions Index types and index signatures function padLeft(value: string, padding: any) { if (​typeof padding === "number") { return Array(padding If we have a value that has a union type, we can only access members that are common to all types in the union  TypeScript now infers the prop function to have a return type of T[K], a so-called indexed access type or lookup type. It represents the type of the property K of the type T . If we now access the three todo properties via the prop method, each one will have the correct type:


TypeScript 2.1 · TypeScript, Enter Index Type Query or keyof ; An indexed type query keyof T yields the type of interface Person { name: string; age: number; location: string; } type K1 The dual of this is indexed access types, also called lookup types. From T pick a set of properties K declare function pick<T, K extends keyof T>(obj: T, keys: K[]​):  An index signature parameter type must be ‘string’ or ‘number’. If you have a type with a string index signature, keyof T will be string | number (and not just string, since in JavaScript you can access an object property either by using strings (object['42']) or numbers (object[42])). And T[string] is just the type of the index signature:


Interfaces in TypeScript: What are they and how do we use them , Indexable types are helpful when you have to define custom properties and functions that should The TeslaModelSReview interface indexes the group of properties the property tempCache has an access modifier private and so it is not interface Wheel { wheelBase: number; controls: Array<string>,  interface NumberDictionary { [index: string]: number; length: number; // ok, length is a number name: string; // error, the type of 'name' is not a subtype of the indexer } However, properties of different types are acceptable if the index signature is a union of the property types: