带有编号索引的Typescript数组接口和可通过字符串键访问的自定义属性

时间:2018-11-14 08:42:09

标签: typescript typescript-typings

我想让对象数组按数字索引,并希望将所有对象放在特定键下的数组中

类似这样的东西:

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

但是我正在努力定义它的接口。首先,我期望类似的东西会起作用,但不会起作用。

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

}

3 个答案:

答案 0 :(得分:1)

您正在做的事情很奇怪,而Typescript团队有意不支持这种奇怪的想法。因此,您必须采取一些怪异的解决方法(对不起,您写过3次“怪异”字样):

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;

怪异之处在于数组和对象的结合。此外,对象可以具有任何键。具有任意键的接口并没有太多好处。

答案 1 :(得分:1)

您的类型的问题在于,它与字符串索引签名([key: string] : IItem;)不一致。如果您继承数组,则并非所有以此方式访问的键都将是IItem类型。例如,myArray['map']将不是数组IItem。这是打字稿强制字符串索引签名与接口的所有静态声明的成员兼容的原因。

尽管此检查中存在漏洞。交叉口类型漏洞。我们可以将ICustomArray声明为数组和具有索引签名的类型的交集。

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

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

这将以您期望的方式工作:

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

答案 2 :(得分:0)

我一直在考虑臭名昭著的TypeScript Dictarray,因为它已经出现了几次。

有一个快速而肮脏的修复程序,基本上可以消除类型创建时的错误。有趣的原因是,如果执行此操作,则类型检查和推断都可以按预期工作。您实际上忽略了Array的所有成员与您的字符串键项之间的冲突。

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

如果使用此类型,则可以有效地完全按照创建类型时的预期进行操作-尽管如果要创建新类型,则可以考虑将它们卡在一起。

您可以使用通用的Dictarray而不是严格的版本:

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

const dictarray = [] as Dictarray<string>;