web-dev-qa-db-ja.com

TypeScriptが「Like」タイプを使用するのはなぜですか?

TypeScriptに型があり、次に「like type」があるのはなぜですか?この例はPromise<T>およびPromiseLike<T>。これら2つのタイプの違いは何ですか?いつ使うべきですか?この場合、1つのPromiseタイプだけではないのはなぜですか?

29
Stewart

定義ファイルを見ると( lib.es6.d.ts を見てみましょう)、とても簡単です。

たとえば、 ArrayLike インターフェース:

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

Array oneよりも制限されています:

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;
}

次のような関数が必要な場合があるため、2つを分離しておくとよいでしょう。

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

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

しかし、これでは動作しません:

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

次のエラーが発生します。

タイプ 'IArguments'の引数は、タイプ 'any []'のパラメーターに割り当てることはできません。
タイプ 'IArguments'にプロパティ 'Push'がありません。

しかし、これを行うと両方が機能します:

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

(詳細は MDNのArrayLike

PromisePromiseLikeについても同様です。Promiseの実装について考えられていないライブラリを構築している場合、これを行う代わりに:

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

これを行います:

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

ライブラリのユーザーが別の実装(bluebird)を使用している場合でも、問題なく動作します。

Promise の定義は次のとおりです。

declare var Promise: PromiseConstructor;

これにより、非常に具体的になりますが、他の実装は異なるプロパティ、たとえば異なるプロトタイプを持つ場合があります。

interface PromiseConstructor {
    readonly prototype: Promise<any>;

    ...
}

私たちがPromiseLikeを持っている主な理由は、ネイティブ実装がサポートされる前にいくつかの実装が利用可能であったためだと思います( bluebirdPromises/A +jQuery など)。
TypeScriptがこれらの実装を使用しているコードベースで動作するには、Promise以外の型が必要です。そうでない場合、多くの矛盾が生じます。

34
Nitzan Tomer