ts类型挑战【十三】

122 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

题目十七:promise-all

// template.ts
declare function PromiseAll(values: any): any
// test-cases.ts
import { Equal, Expect } from '@type-challenges/utils'

const promiseAllTest1 = PromiseAll([1, 2, 3] as const)
const promiseAllTest2 = PromiseAll([1, 2, Promise.resolve(3)] as const)
const promiseAllTest3 = PromiseAll([1, 2, Promise.resolve(3)])

type cases = [
  Expect<Equal<typeof promiseAllTest1, Promise<[1, 2, 3]>>>,
  Expect<Equal<typeof promiseAllTest2, Promise<[1, 2, number]>>>,
  Expect<Equal<typeof promiseAllTest3, Promise<[number, number, number]>>>
]

键入函数PromiseAll,它接受PromiseLike对象数组,返回值应为Promise<T>,其中T是解析的结果数组。

测试用例

  • 示例1
const promiseAllTest1 = PromiseAll([1, 2, 3] as const) // 期望:Promise<[1, 2, 3]>

[1, 2, 3] as const 会将 [1, 2, 3]作为具体的类型传入 PromiseAll,期望值是 Promise<[1, 2, 3]>,说明只需要简单的遍历并输出即可

  • 示例2
const promiseAllTest2 = PromiseAll([1, 2, Promise.resolve(3)] as const) // 期望:Promise<[1, 2, number]>

这个示例不同的点在于数组中的第三个参数是一个 Promise 类型,这个 Promise 类型中传入的数值 3。同时,期望的值在该位置变为 number,也就是数值 3 的类型

这里可以判断:如果传入的数组中Promise 类型,则返回值相应的位置会输出对应 Promise 中接收的类型

  • 示例3
const promiseAllTest3 = PromiseAll([1, 2, Promise.resolve(3)]) // 期望:Promise<[number, number, number]

as const操作的作用是将相应的值变为类型,这个示例中没有使用 as const,则期望的结果对应位置全部是相应值的类型

代码实现

  • 原代码
declare function PromiseAll(values: any): any
  • values 类型

values 类型应该是一个数组,数组中可能是任意类型(使用 unknown

declare function PromiseAll(values: unknown[]): any

在外部使用 as const 操作后,相应的类型会变为 readonly 的,所以 values 接收的时候,也需要加上 readonly 修饰符

declare function PromiseAll(values: readonly unknown[]): any
  • 传入的 values 类型,后面也会用到,所以使用泛型 T 来表示
declare function PromiseAll<T extends unknown[]>(values: readonly [...T]): any

这里如果时间使用 values: readonly T 的话会报错:仅允许对数组和元组文本类型使用 "readonly" 类型修饰符。

因为 T 继承 unknown[],但不一定是数组

  • 最后返回一个 Promise 类型,并且 Promise 的参数是一个数组
declare function PromiseAll<T extends unknown[]>(values: readonly [...T]): Promise<[]>
  • 对返回值 Promise 的参数数组进行遍历
declare function PromiseAll<T extends unknown[]>(values: readonly [...T]): Promise<{
  [P in keyof T]: T[P]
}>
  • 如果遍历的内容 T[P]Promise 类型的话,则返回该 Promise 的入参类型
declare function PromiseAll<T extends unknown[]>(values: readonly [...T]): Promise<{
  [P in keyof T]: T[P] extends Promise<infer R> ? R : T[P]
}>