Typescript 泛型数组上的映射推断出错误的类型

Typescript 泛型数组上的映射推断出错误的类型,typescript,generics,Typescript,Generics,在下面的示例中,我注意到了意外的交互。当我尝试将映射到通用的选项时,里面的项目不是我所期望的类型 const foo = <T extends string[]>(options: T, labels: Record<T[number], string>): string[] => { return options.map(o => labels[o]); } 为string数组项创建类型参数T,而不是为数组创建类型参数: const foo=( 选

在下面的示例中,我注意到了意外的交互。当我尝试将映射到通用的选项时,里面的项目不是我所期望的类型

const foo = <T extends string[]>(options: T, labels: Record<T[number], string>): string[] => {
    return options.map(o => labels[o]);
}

string
数组项创建类型参数
T
,而不是为数组创建类型参数:

const foo=(
选项:T[],标签:记录):字符串[]=>{
返回options.map(o=>labels[o]);
}
foo([“A”,“B”]作为[“A”,“B”]{
A:“标签A”,
B:“标签B0”,
})

这是因为映射类型不正确,还是这是预期的行为

预计标签[o]处会出现错误。在您的示例中,
标签
是一种
记录
类型,因此您可以使用类型为
T[number]
的键对其进行索引

现在,当您在
选项
上调用
映射
时,TS将使用
T
string[]
)的基本约束来推断项目类型
string
——这是常见基本类型的最佳选择,我们在这里可以看到。而且
string
不能分配给
T[number]
,因此您在这里得到一个错误


通过使用固定键,我们可以确保记录键和数组项的类型相同。

o
是一个
string
,因为您将T定义为
string[]
。如果希望
o
是一个数字,那么它应该是T,因为
number[]
T
不是
字符串[]
,它只是扩展了它。示例中的任何内容都与数字无关。“但是,map函数表示它的o控制变量的类型为string。”---如果没有
字符串,您希望看到什么?
T[number]
类型更具体。当f.e.I将泛型设置为
T扩展[“A”,“B”]
时,
o
被推断为
“A”|“B”
。既然像这样的字符串文字数组扩展了字符串数组,那么映射函数不应该期望这样的用例,而不仅仅是将
string
放在那里吗?您没有解释
t[number]
工作不正确的原因,据我所知,这是问题的核心。添加第二个
K
参数感觉像是写了一些不必要的东西,但我现在明白了为什么会出现这个问题。我仍然觉得它没有发挥应有的作用,但TS就是这样工作的。@MarošBeťko如果你声明
,很难说出
T
的实际项目类型是什么,也很难将该类型与
T[number]
匹配。通过仅为项类型声明类型参数并完全忽略数组类型,可以进一步简化示例。对于您的示例来说,这应该足够了,请查看编辑后的答案。干杯
foo(["A", "B"] as ["A", "B"], {
    A: "Label A",
    B: "Label B",
})
const foo = <T extends string>(
    options: T[], labels: Record<T, string>): string[] => {
    return options.map(o => labels[o]);
}

foo(["A", "B"] as ["A", "B"], {
    A: "Label A",
    B: "Label B0",
})