打字稿:`| 的含义[T]`-用于数组中元素成员资格的编译时检查的约束

Posted

技术标签:

【中文标题】打字稿:`| 的含义[T]`-用于数组中元素成员资格的编译时检查的约束【英文标题】:TypeScript: Meaning of `| [T]`-constraint for compile-time checks of element membership in arrays 【发布时间】:2021-03-01 15:13:03 【问题描述】:

我想编写一个函数f,它接受A 类型的单个参数,其中A 必须是包含特定类型T 的元素的数组。为简单起见,假设T = 'ok'(字符串'ok' 的单一类型)。

利用this answer的思路,初步得到如下解决方案:

function f<
  E,
  A extends (ReadonlyArray<E> | [E]) & [K in keyof A]: [T in K]: 'ok'[number]
>(a: A) 

正如上面引用的答案,它确实有效。

但我无法理解| [E]-part,所以我决定检查是否可以删除它,或者用另一种类型替换它:

function f<
  E, 
  X, 
  A extends (ReadonlyArray<E> | [X]) & [K in keyof A]: [T in K]: 'ok'[number]
>(a: A) 

这也有效,即它可以区分带有或不带有元素 'ok' 的数组:

f(['a', 'b', 'ok', 'z']) // compiles, good
f(['a', 'b', 'z'])       // does not compile, good

我的问题是,如果我删除 [X] 部分,我无法理解为什么它不起作用。它似乎与代码中发生的任何事情完全无关:

[X] 的数量与元组的数量不匹配 X 类型实际上并不与任何东西相关联,它没有包含EAstring'ok' 或其他任何东西的边界。

| [X] 到底在做什么?

【问题讨论】:

【参考方案1】:

我们举个简单的例子:

function foo<T extends number[]>(t: T): T  return t 
foo([1, 2, 3]) // number[]

将推断出一个数组返回类型。

function foo2<T extends number[] | [number]>(t: T): T  return t 
foo2([1, 2, 3]) // [number, number, number]

| [number] forces TypeScript to infer a tuple 代替数组,不使用as const(如果你愿意的话,这是一个隐藏的编译器规则)。

您甚至可以通过为扩展原始类型的数组项添加类型参数 R 来保持数字文字的范围:

function foo3<R extends number, T extends R[] | [R]>(t: T): T  return t 
foo3([1, 2, 3]) // [1, 2, 3]

Playground

【讨论】:

“一个隐藏的编译器规则” - 这个隐藏的规则有任何非正式的名称,还是在任何地方的任何官方文档中都提到过? 它不是官方 TS 手册的一部分,但语言创建者 Anders Hejlsberg 本人在 GitHub 问题中提到它是有效的解决方法。所以我们可以假设,它在这里停留在编译器中。我需要再次搜索具体问题,目前没有链接。 你的意思是:github.com/microsoft/TypeScript/issues/… ? 是的,确实如此。尤其是之前的一条评论:github.com/microsoft/TypeScript/issues/… 您能否在您的答案中更突出地链接它,这样很明显,这是 Hejlsberg 本人认可的东西? (或者,如果您不介意,我可以将链接编辑到您的答案中)

以上是关于打字稿:`| 的含义[T]`-用于数组中元素成员资格的编译时检查的约束的主要内容,如果未能解决你的问题,请参考以下文章

打字稿类型检查不适用于数组过滤器

打字稿,将键限制为数组元素

查找累积和反应打字稿

打字稿中数组的两种写作有啥区别

如何在打字稿中定义一个常量数组

在打字稿中返回反应 16 个数组元素