【问题标题】:Why does TypeScript use "Like" types?为什么 TypeScript 使用“Like”类型?
【发布时间】:2017-05-01 00:16:22
【问题描述】:

为什么 TypeScript 有一个类型,然后是一个“相似类型”?这方面的一个例子是Promise<T>PromiseLike<T>

这两种类型有什么区别?我应该什么时候使用它们?在这种情况下,为什么不只使用一个 Promise 类型?

【问题讨论】:

  • 如果我问你关于 Arrays 和 ArrayLike 对象以及它们之间的区别,你会怎么回答?
  • 你看过definition in the lib吗?
  • 感谢您的链接。很高兴看到定义的类型,但是这个问题更关注两种类型之间的语义差异,而不仅仅是它们的接口。定义这两种类型的目的是什么?为什么作者选择这样做?我认为@Thomas 暗示这里存在正交 API 设计内涵。这些是什么?涵盖其中一些更大的设计问题的答案就是我所追求的。如果你愿意,我可以更新问题的措辞。
  • 原因是Promise 除了原生的(蓝鸟等)还有其他的实现,那就是PromiseLike。数组也是如此,例如argumentsArrayLike,但不是Array。如果你返回一个Promise,如果定义上写着PromiseLike,它应该可以工作。请将您的实际代码添加到问题中,您可能还有另一个问题。
  • @NitzanTomer 感谢您的 cmets。我已经更新了这个问题,使其更符合我最初应该问的问题。

标签: javascript typescript types promise


【解决方案1】:

如果您查看定义文件(让我们以lib.es6.d.ts 为例),那么它非常简单。

例如ArrayLike接口:

interface ArrayLike<T> {
    readonly length: number;
    readonly [n: number]: T;
}

Array 更有限:

interface Array<T> {
    length: number;
    toString(): string;
    toLocaleString(): string;
    push(...items: T[]): number;
    pop(): T | undefined;
    concat(...items: T[][]): T[];
    concat(...items: (T | T[])[]): T[];
    join(separator?: string): string;
    reverse(): T[];
    shift(): T | undefined;
    slice(start?: number, end?: number): T[];
    sort(compareFn?: (a: T, b: T) => number): this;
    splice(start: number, deleteCount?: number): T[];
    splice(start: number, deleteCount: number, ...items: T[]): T[];
    unshift(...items: T[]): number;
    indexOf(searchElement: T, fromIndex?: number): number;
    lastIndexOf(searchElement: T, fromIndex?: number): number;
    
    // lots of other methods such as every, forEach, map, etc

    [n: number]: T;
}

最好将两者分开,因为我可能想要这样的函数:

function getSize(arr: Array<any>): number {
    return arr.length;
}

console.log(getSize([1, 2, 3])); // works

但它不适用于此:

function fn() {
    console.log(getSize(arguments)); // error
}

结果是这个错误:

“IArguments”类型的参数不能分配给类型参数 '任何[]'。
“IArguments”类型中缺少属性“push”。

但如果我这样做,两者都会起作用:

function getSize(arr: ArrayLike<any>): number {
    return arr.length;
}

(更多关于ArrayLike in MDN

PromisePromiseLike 相同,如果我正在构建一个对Promise 的实现没有意见的库,那么不要这样做:

function doSomething(promise: Promise<any>) { ... }

我会这样做的:

function doSomething(promise: PromiseLike<any>) { ... }

那么即使我的库的用户使用不同的实现(蓝鸟),它也可以正常工作。

如果你注意到Promise 的定义是这样的:

declare var Promise: PromiseConstructor;

这使得它非常具体,其他实现可能具有不同的属性,例如不同的原型:

interface PromiseConstructor {
    readonly prototype: Promise<any>;

    ...
}

我猜我们拥有PromiseLike 的主要原因是在支持原生实现之前有多种实现可用(例如bluebirdPromises/A+jQuery 等)。
为了使 typescript 与使用这些实现的代码库一起工作,必须有一个不是 Promise 的类型,否则会有很多矛盾。

【讨论】:

  • 很好的答案,但在这种特殊情况下,我仍然感到困惑。为什么catch()PromiseLike 中会有问题?
  • @rekire 我不知道他们为什么选择在PromiseLike 中只包含then,但我猜一些promise 实现没有catch(例如它看起来像@ 987654329@不要)。
  • 非常感谢,它救了我的命。
猜你喜欢
  • 2021-09-03
  • 2018-07-27
  • 1970-01-01
  • 2020-03-05
  • 2017-12-23
  • 2019-08-06
相关资源
最近更新 更多