我有一种类型,如下:

type GetUnion<T extends any[]> = T[number];
type Foo = GetUnion<[1, 2]>;  // 1 | 2

Playground

我知道"number"类型代表所有可能数字的并集,所以T[number]应该像T[0 | 1 | 2 | 3 | ...],应该是T[0] | T[1] | T[2] | T[3] | ...,也就是1 | 2 | undefined.但为什么实际值只有1 | 2而不是1 | 2 |undefined

推荐答案

[1, 2]这样的Tuple typesarray types的子类型,因此具有与数组的元素类型相对应的数字index signatures.也就是说,the Array<T> declaration includes

interface Array<T> {
  [n: number]: T 
}

请注意,这是T而不是T | undefined,即使当您从数组的任意数字索引读取时,也很可能得到undefined的结果.当你使用像Array<T>[number]这样的indexed access type时,你得到的是属性类型T,而不是T | undefined.

这一行为早于null/undefined checking的存在.一旦你可以预料到| undefined会出现在可能未定义的类型上,人们就开始要求索引签名做这件事,microsoft/TypeScript#13778获得了很多社区的支持.但打字团队has always been skeptical认为这实际上是可取的.强迫人们判断undefined的索引签名将导致许多惯用的JavaScript无法编译.尽管如此,它仍然很受欢迎,所以最终引入了a --noUncheckedIndexedAccess compiler flag来实现它,这样当您从具有索引签名的类型读取时,您必须判断undefined.这是在microsoft/TypeScript#39560中实施的,其中解释说:

Design Point: What's the type of T[number] / T[string] ?

在实现此功能时,会给出以下类型的问题:

type Q = (boolean[])[number];

Q应该是boolean(合法写入数组的类型)还是boolean | undefined(如果从数组中读取就会得到的类型)?

判断此代码:

// N.B. not a good function signature; don't do this in real code
function zzz<T extends unknown[]>(arr: T, i: number): T[number] {
    return arr[i];
}

感觉在这种模式下,判断员的工作就是说"zzz进行可能超出范围的读取,需要澄清".然后,您可以编写以下任一代码:

// Allows out-of-bounds access to silently occur
function zzz1<T extends unknown[]>(arr: T, i: number): T[number] | undefined {
    return arr[i];
}
// - or - 
// Bounds checks for you
function zzz2<T extends unknown[]>(arr: T, i: number): T[number] {
    // TODO: Validate that 'i' is in bounds
    return arr[i]!; // ! - safety not guaranteed but we tried
}

这有very的积极副作用,它意味着声明文件中的T[number]不会根据是否设置了标志而改变含义,并保持

type A = { [n: number]: B }[number]
// A === B

简而言之,他们决定让T[number]成为索引的较窄的write类型,而不是较宽的read类型,这样返回边界之外的实际值就是类型T[number] | undefined,并且声明文件和以前识别的类型标识不会改变. 无论人们是否同意这些理由,这似乎是这个问题的标准答案.

Typescript相关问答推荐

React组件数组及其props 的类型定义

React-Native运行方法通过监听另一个状态来更新一个状态

有没有可能使用redux工具包的中间件同时监听状态的变化和操作

TypeScript类型不匹配:在返回类型中处理已经声明的Promise Wrapper

将props传递给子组件并有条件地呈现它''

输入元素是类型变体的对象数组的正确方法是什么?'

异步动态生成Playwright测试,显示未找到测试

类型{}上不存在属性&STORE&A;-MobX&A;REACT&A;TYPE脚本

我可以为情态车使用棱角形的路由守卫吗?

如何正确调用创建的类型?

如何创建由空格连接的多个字符串的类型

类型脚本-在调用期间解析函数参数类型

如何将类似数组的对象(字符串::匹配结果)转换为类型脚本中的数组?

字幕子集一个元组的多个元素

埃斯林特警告危险使用&as";

来自枚举的<;复选框和组件列表

为什么TS条件返回要求不明确的强制转换而不是精确的强制转换?

如何在Vuetify 3中导入TypeScript类型?

有没有一种简单的方法可以访问Keyboard Shortcuts JSON文件中列出的每个命令的显示名称(标题)?

覆盖高阶组件中的 prop 时的泛型推理