ts 类型推断疑惑?

function setDictionary<T>(
  data: T,
  label: keyof T,
  dictionaryOptions: { [key in keyof T]: { [key: string | number]: any }[] }
) {
  const options = dictionaryOptions[label];
}

image.png

options 怎么会是这个类型?应当是{ [key: string | number]: any }[] 才对啊。
是哪里出了问题?如何解决呢?

"vue-tsc": "^1.8.27"

阅读 662
avatarAI BotBETA

在 TypeScript 中,类型推断的规则相当复杂,这里涉及到了一些高级的类型推断技巧。让我们首先理解一下你的函数和代码中的类型推断是如何工作的。

首先,label 的类型是 keyof T,这意味着 labelT 类型的键。然后,你试图从 dictionaryOptions 对象中获取与 label 对应的值。

dictionaryOptions 是一个映射类型,它的键是 T 类型的键,值是 { [key: string | number]: any }[] 类型的数组。

当你尝试从 dictionaryOptions 中获取与 label 对应的值时,TypeScript 会尝试推断出这个值的类型。

由于 labelkeyof T 类型,并且 dictionaryOptions 的键也是 keyof T 类型,TypeScript 可以推断出 options 的类型是 { [key: string | number]: any }[]

这个推断是基于 TypeScript 的映射类型和索引签名的推断规则。当你有一个映射类型和一个索引操作时,TypeScript 会使用映射类型的对应规则来推断结果类型。

在你的例子中,映射类型是 { [key in keyof T]: { [key: string | number]: any }[] },这意味着对于任何 K in keyof T,如果我们在该映射上使用一个索引操作 dictionaryOptions[K],那么结果类型将是 { [key: string | number]: any }[]

因此,当你使用 label 作为索引来获取 options 时,TypeScript 推断出 options 的类型是 { [key: string | number]: any }[],这是正确的。

所以,options 的类型并不是你预期的 { [key: string | number]: any }[],而是正确的类型。如果你想确保 options 的类型是你期望的类型,你可能需要重新考虑你的函数设计或使用类型断言来明确指定你期望的类型。

3 个回答

看了下如果这里是一个精确类型就能推导出来

type Data = { name: string, age: string }

function setDictionary(
    data: Data,
    label: keyof Data,
    dictionaryOptions: { [key in keyof Data]: { [key: string | number]: any }[] }
) {
    const options = dictionaryOptions[label];
}

image.png

但如果是泛型就不行,不知道是刻意没有处理这种情况还是 vscode 插件的问题

dictionaryOptions: { [key in keyof T]: Record<string | number, any>[] }

本质问题是

type a = { [key: string | number]: any } 

显示为

type c = {
    [key: string]: any;
    [key: number]: any;
}

因为 JS 中不存在数字类型的Key, 即使取值时数字也会被转为字符串, 所以不存在key的类型是 string | number

ts 会拆分成独立的索引类型,更能描述js 的行为

logo
Microsoft
子站问答
访问
宣传栏