类型中的
括号仅用于分组和解决歧义;它们不会修改它们所包围的类型。例如,给定类型
type A = { a: 1, c: 3 };
type B = { b: 2, c: 3 };
那么这个类型解析成什么?
type Z = keyof A | B; // ??
使用括号,您可以明确说明您的解释方式:
type X = (keyof A) | B; // "a" | "c" | B
type Y = keyof (A | B); // "c"
事实证明,keyof 与 A 的绑定比联合运算符 | 更紧密,所以 Z 等价于 X... 所以如果你的意思是 Y,你需要这些括号.
(越来越过时的)TypeScript Specification document 说:
当它们用作数组元素类型时,联合、交集、函数或构造函数类型需要括号;围绕交集类型中的联合、函数或构造函数类型;以及联合类型中的函数或构造函数类型。
如有疑问,请添加括号。
类型中的
方括号实际上有多种不同的含义:
-
当T 类型后面紧跟一对empty 方括号时,表示一个数组,其元素为T 类型,等价于到Array<T>。所以{a: string}[] 是一个数组,其元素的类型为{a: string},并且等价于Array<{a: string}>。 (类似地,如果这种类型的前面紧跟readonly 修饰符,如readonly T[],那么它等价于ReadonlyArray<T>。)
-
当一个类型 T 紧跟在方括号中的另一个类型 U (即T[U])...括号不是空的,这意味着你looking up or indexing T 的属性类型,其键为 U 类型。所以{a: string}["a"]是{a: string}的a属性的类型...即string。而Array<boolean>[number] 是当您使用number 键索引到Array<boolean> 时获得的类型......即boolean。
-
当方括号包含零个或多个类型的逗号分隔列表时,例如 [] 或 [T] 或 [T,U] 或 [T,U,V] 等,(如果它是零或一,你需要小心不要将其与上面的数组或查找符号混淆),然后您指定tuple 类型,该数组具有固定数量的可能不同类型的元素以固定顺序排列。元组类型也可以在readonly 前面加上readonly tuples,元组还有其他有趣的事情,比如rest and optional elements in tuple types 和variadic tuple types,所以readonly [0, ...[1, 2, 3], 4?, ...[5?, 6?, 7?], ...8[]] 是一个有效的TS 类型(在TS4.0 +)。
有了这些,让我们看看这些例子:
type ArrayTypes<T> =
T extends (infer U)[]
? U
: never
这就是说:给定一个类型T,如果它扩展了某个数组类型U[],其中U将被推断出来,则返回U,否则返回never。 infer 需要附加到 U。无论出于何种原因,[] 比infer 绑定得更紧密,因此T extends infer U[] 将被解释为T extends infer (U[])...这是无效的,因为您只能infer 一个新类型变量,而不是这样的函数一个变量。这就是你需要括号的原因。
let arr = [1, "2", []];
type test = ArrayTypes<typeof arr> // type test = string | number | never[]
这很有道理,对吧? arr 被推断为Array<string | number | Array<never>> 或等效的(string | number | never[])[] 类型,因此ArrayTypes<typeof arr> 推断U 为string | number | never[],这就是你得到的。 (请注意,在我使用的 TS 版本中,[] 的值被推断为类型 never[],而不是 any[])。
另外请注意,上面带有number 键的查找类型在不需要infer 的情况下执行相同的操作:
type ArrayTypes<T> = T extends any[] ? T[number]: never;
下一个例子:
type ArrayTypes<T> =
T extends (infer U)
? U
: never
这里的括号不是必需的,因为没有歧义。你可以写T extends infer U ? U : never。这意味着:给定一个类型T,它扩展了一些推断类型U,返回U;否则返回never。但这似乎有点傻,因为U 将永远被推断为T,因此ArrayTypes<T> 将永远是T,无论如何:
let arr = [1, "2", []];
type test = ArrayTypes<typeof arr> // type test = (string | number | never[])[]
test 类型将与typeof arr 相同,即Array<string | number | Array<never>>,或等效的(string | number | never[])[]。
我希望这可以为您澄清事情。祝你好运!
Playground link to code