【TS】如何在 typescript 中将数组字面量推断到 tuple

6 篇文章 0 订阅

在 ts 中推断到 tuple 的实践方案

Tuple 保留了数组内容的更多信息,包括数组长度,以及每个元素的类型(尤其是字面量类型)和元素之间的相对位置。

尝试一下 实现 Promise.all 的类型

一个比较优秀的实现是:

declare function PromiseAll<A extends any[]>(values: readonly [...A]): Promise<{
  [key in keyof A]: Awaited<A[key]>
}>

其中 [...A] 用于显式将参数类型推断为 tuple,而不是更宽的数组类型 type[]

不过,typescript 标准库里是这样实现的:

/**
 * Creates a Promise that is resolved with an array of results when all of the provided Promises
 * resolve, or rejected when any Promise is rejected.
 * @param values An array of Promises.
 * @returns A new Promise.
 */
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;

注意到它没有使用 [...T],而是将泛型 T 的约束变成了一个 union type ... | [],追加了一个空 tuple 类型。

而当类型中包含 tuple 时,编译器会先一步**推断(inference)该类型为 tuple,尽管在下面这个例子中,参数的类型在可分配性(assignability)**上存在问题,但参数仍然被推断为 tuple。

declare function PromiseAll<T extends (readonly unknown[]) | []>(values: T): Promise<{
  -readonly [key in keyof T]: Awaited<T[key]>
}>

const promiseAllTest3 = PromiseAll([1, 2, 3]) // Promise<[number, number, number]>

如果我们去掉这个导致 tuple 推断的 ... | [],我们会观察到,参数失去了 tuple 的性质,变为了更宽的 number[] 类型。

实际上追加的 tuple 类型是什么并无所谓,即便使用 ... | [string],在上面的 case 中也是 work 的。

declare function PromiseAll<T extends readonly unknown[]>(values: T): Promise<{
  -readonly [key in keyof T]: Awaited<T[key]>
}>

const promiseAllTest3 = PromiseAll([1, 2, 3]) // Promise<number[]>

所以,作为参数的接收方,我们现在拥有了两个方案来让 ts 编译器将字面量推断到 tuple。

  • 使用 spread operator。
  • 使用任意 tuple 字面量作为泛型约束,必要时可以使用 union type 来绕过可分配性检查。

ref

type-challenges/promise-all

stackoverflow#74848194

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高厉害

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值