如何阅读TypeScript的复杂interface?

看到一个interface的声明,非常复杂:

interface PromiseLike<T> {
    /**
     * Attaches callbacks for the resolution and/or rejection of the Promise.
     * @param onfulfilled The callback to execute when the Promise is resolved.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of which ever callback is executed.
     */
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;
}

1、这个很难看懂,请问一下,应该如何学习这个定义呢?
是否可以拆分一点一点地学到它的含义?

2、需要带着什么样的思路才能去看懂,从想要定义它的目的去阅读吗?

阅读 781
avatarAI BotBETA

1、如何学习这个定义?

学习这个PromiseLike<T>接口的定义时,可以将其拆分为几个部分来理解:

  • 接口名称与泛型参数interface PromiseLike<T>表明这是一个接口,它接受一个泛型参数T,这个T代表了Promise解析成功时返回的值类型。
  • 方法定义:接口内定义了一个方法then,这是Promise和类Promise对象的核心方法之一。
  • 方法签名then方法的签名相对复杂,因为它涉及到泛型的条件类型(TResult1 = T, TResult2 = never)以及多个可选参数(onfulfilled?, onrejected?)。
  • 参数说明

    • onfulfilled:当Promise成功解析时调用的函数,该函数可以返回一个新的值(TResult1类型)或一个新的PromiseLike<TResult1>对象。
    • onrejected:当Promise被拒绝时调用的函数,该函数可以返回一个新的值(TResult2类型)或一个新的PromiseLike<TResult2>对象。
  • 返回值then方法返回一个PromiseLike<TResult1 | TResult2>,即根据onfulfilledonrejected的返回值类型,返回一个新的PromiseLike对象。

2、阅读复杂接口的思路

  • 理解目的:首先明确接口设计的目的。对于PromiseLike<T>,其目的是提供一个与Promise类似行为的类型定义,允许非Promise对象也能拥有链式调用.then()的能力。
  • 分步骤解析

    • 泛型参数:理解泛型T的作用,即它代表什么。
    • 方法签名:逐个分析方法的参数和返回类型。特别是要注意参数的默认值、可选性,以及返回类型的计算方式。
    • 注释与文档:利用JSDoc注释理解每个参数和方法的意图。
  • 关联知识:了解Promise的基本工作原理,特别是.then()方法的行为,对于理解PromiseLike<T>接口至关重要。
  • 实践应用:通过编写代码示例来加深理解,尝试创建符合PromiseLike<T>接口的对象,并模拟其.then()方法的行为。

通过上述步骤,你可以逐步深入理解复杂接口的定义,并能够在自己的项目中灵活应用。

4 个回答

最简单的方法是,写实际的例子去进行对比,当然前提是熟悉 promise 怎么使用。

type IsEqual<T1, T2> = T1 extends T2 ? (<G>() => G extends T1 ? 1 : 2) extends <G>() => G extends T2 ? 1 : 2 ? true : false : false
type AnyIsEqual<T1, T2> = T1 extends T2 ? IsEqual<T1, T2> extends true ? true : never : never
type BrowserNativeObject = Date | FileList | File
type Primitive = null | undefined | string | number | boolean | symbol | bigint
type PathImpl<K extends string | number, V, TraversedTypes> = V extends Primitive | BrowserNativeObject ? `${K}` : true extends AnyIsEqual<TraversedTypes, V> ? `${K}` : `${K}` | `${K}.${PathInternal<V, TraversedTypes | V>}`
type TupleKeys<T extends ReadonlyArray<any>> = Exclude<keyof T, keyof any[]>
type ArrayKey = number
type PathInternal<T, TraversedTypes = T> = T extends ReadonlyArray<infer V> ? IsTuple<T> extends true ? {
  [K in TupleKeys<T>]-?: PathImpl<K & string, T[K], TraversedTypes>;
}[TupleKeys<T>] : PathImpl<ArrayKey, V, TraversedTypes> : {
  [K in keyof T]-?: PathImpl<K & string, T[K], TraversedTypes>;
}[keyof T]
type Path<T> = T extends any ? PathInternal<T> : never

这个例子看起来就非常复杂,但是如果写一个例子放上去,很容易就知道这是做什么,如果不写例子估计看半天都不知道干什么的

interface PromiseLike<T> {
    /**
     * Attaches callbacks for the resolution and/or rejection of the Promise.
     * @param onfulfilled The callback to execute when the Promise is resolved.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of which ever callback is executed.
     */
    then<TResult1 = T, TResult2 = never>(
//      ^ 尖括号之间是泛型                ^
//       ^^^^^^^^^^^^ 第一个类型参数是 TResult1,默认类型为 T(即 interface 中定义的泛型 T)
//                     ^^^^^^^^^^^^^^^^ 第二个类型参数是 TResult2,默认类型是 never
        onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
//      ^^^^^^^^^^^ then 函数的第一个参数,冒号后面是这个参数的类型
//                    ^                                              ^ ^           ^ 参数类型是 3 个类型的联合
//                     ^         ^^^^^  从这个特征可以看出来这是一个函数类型(回调)
//                                                                     ^^^^^^^^^^^^^^^^^^ 这两个类型不用多说了
//                      ^^^^^^^^ 函数参数是 T,也就是 PromiseLike<T> 带出来的值类型
//                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 结果回调处理的结果,TResult1 或者 PromiseLike<TResult1>
//                                                                    因为 TResult1 是个泛型,所以存在 undefined 或者 null 的
//                                                                    可能性。undefined 就是常见没有返回值的情况
        onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
//                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                                 参考上面的类型分析,这里 TResult2 表示 resolve 和 reject 可能会处理不同的类型
//                                 实际也是,resolve 的是正常值,而 reject 出来的通常是一个错误对象
    ): PromiseLike<TResult1 | TResult2>;
//                 ^^^^^^^^^^^^^^^^^^^ 因为 then 处理了 resolve 和 reject 的情况,所以有可能是两种类型的返回值
}

可以了解 type-challenges 这个项目,这个项目有涉及很多复杂类型的定义,很多人给了不同的实现和这样子写的理由,可以由浅及深,一开始就来那么复杂是比较难看懂的,了解一些简单结构的原理,后面看到复杂的结构会慢慢发现也是从几个简单的结构组成,这个 PromiseLike 里面也有

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Microsoft
子站问答
访问
宣传栏