TypeScript: `| [T]` 的含义 - 用于编译时检查数组中元素成员身份的约束

标签 typescript types tuples mapped-types

我想编写一个函数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]-部分,所以我决定检查是否可以删除它,或者用另一种类型替换它:

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实际上并不与任何东西绑定(bind),它没有包含EAstring<的边界'ok' 或其他任何内容。

什么是| [X]到底在做什么?

最佳答案

举个简单的例子:

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]

| [号码] 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

关于TypeScript: `| [T]` 的含义 - 用于编译时检查数组中元素成员身份的约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64891603/

相关文章:

JavaScript map(),集合中对象的未定义属性

javascript - 有没有办法在 Typescript 的包装函数中动态键入函数?

c++ - 从元组中提取 vector

swift - 使用语句 For 写入元组

android - 为什么 Ionic 键盘事件没有触发?

angular - 类型 'share' 上不存在属性 'Navigator'

php - 启用严格类型后,array_map 无论如何都会转换类型

rust - 如何将元组作为参数传递以便在稳定的 Rust 中顺序应用具有多个返回值的函数?

testing - 测试对象是否符合 TypeScript 中的接口(interface)

haskell - "Free"类型变量受类型同义词中的功能依赖关系约束