TypeScript - 如何将索引签名表示为通用类型

TypeScript - How to represent an index signature as a generic type

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
}

由于以下错误无法编译:

An index signature parameter must be of type 'string' or 'number'.

这不可能吗?

这到底是为了什么?

因为

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 })

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

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

但为什么不这样做呢

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

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

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

它不像您的解决方案那么整洁,但作为一种妥协,它似乎还可以,因为 XXXIndex 类型集限制为 2

另一种解决方案是使用 Record 实用程序。

foo(obj: Record<string, Bar>)

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