15

TypeScript 中的索引签名是这样定义的:

字典

[key: string]: T

大批

[index: number]: T

这些可以包装成一些简单的、可重用的类型:

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

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

现在我想将它们包装成一个类型。我试过这个:

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

由于以下错误,这无法编译:

索引签名参数必须是“字符串”或“数字”类型。

这不可能吗?

到底是为了什么?

因为

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

看起来比

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

2 回答 2

5

很酷的问题!
我认为原因是这对于尚未实现的编译器来说确实是一个边缘案例,可能是因为它不值得付出努力。

索引属性键只能是明显的数字,对象属性键只能是字符串或数字。所以最后你的约束只说明什么是事实,以及编译器需要通过特殊情况处理什么。
所以我再次假设圣安德斯放弃了这一努力;-)

但为什么不这样做

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

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

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

它不像您的解决方案那样简洁,但作为一种折衷方案,它似乎还可以,因为 XXXIndex 类型的集合限制为 2

于 2017-02-10T10:12:07.817 回答
0

一种替代解决方案是使用该Record实用程序。

foo(obj: Record<string, Bar>)

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

于 2022-02-02T15:55:42.623 回答