1. ホーム
  2. javascript

TypeScriptはなぜ "Like "型を使うのか?

2023-09-05 19:41:23

質問

TypeScriptにはなぜ型があり、さらに"like type"があるのでしょうか?例として Promise<T>PromiseLike<T> .

この2つのタイプの違いは何ですか?どのような場合に使用するのでしょうか?この場合、なぜ1つの Promise タイプにすればいいのでは?

どのように解決するのですか?

定義ファイルを見てみると(仮に lib.es6.d.ts を例にとります) を見れば、かなりわかりやすいと思います。

例えば ArrayLike インタフェースがあります。

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

配列 よりも制限されています。

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[]' 型のパラメータに代入できません。 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 がサポートされる前に、いくつかの実装が利用可能だったことです (例えば ブルーバード , 約束/A+(プラス , jQuery など)。

typescriptがこれらの実装を使用しているコードベースで動作するためには、以下のようなタイプでなければなりません。 Promise でなければならず、そうでなければ多くの矛盾が生じます。