web-dev-qa-db-fra.com

Pourquoi TypeScript utilise-t-il des types "similaires"?

Pourquoi TypeScript a-t-il un type puis un "type similaire"? Un exemple de ceci est Promise<T> et PromiseLike<T>. Quelles sont les différences entre ces deux types? Quand dois-je les utiliser? Dans ce cas, pourquoi ne pas avoir un seul type Promise?

29
Stewart

Si vous regardez les fichiers de définition (prenons lib.es6.d.ts ) alors c'est assez simple.

Par exemple, l'interface ArrayLike :

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

est plus limité que le 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;
}

C'est bien d'avoir les deux séparés parce que je pourrais vouloir avoir une fonction comme celle-ci:

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

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

Mais cela ne fonctionnera pas avec ceci:

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

Il en résulte cette erreur:

L'argument de type "IArguments" n'est pas attribuable au paramètre de type "any []".
La propriété 'Push' est manquante dans le type 'IArguments'.

Mais les deux fonctionneront si je fais cela:

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

(plus sur ArrayLike dans MDN )

La même chose avec Promise et PromiseLike, si je construis une bibliothèque qui n'est pas d'opinion sur l'implémentation de Promise alors au lieu de faire ceci:

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

Je vais faire ça:

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

Ensuite, même si l'utilisateur de ma bibliothèque utilise une implémentation différente (bluebird), cela fonctionnera très bien.

Si vous remarquez la définition de Promise est la suivante:

declare var Promise: PromiseConstructor;

Ce qui le rend très spécifique, d'autres implémentations peuvent avoir des propriétés différentes, par exemple un prototype différent:

interface PromiseConstructor {
    readonly prototype: Promise<any>;

    ...
}

Je suppose que la principale raison pour laquelle nous avons PromiseLike est que plusieurs implémentations étaient disponibles avant que la native ne soit prise en charge (comme bluebird , Promises/A + , jQuery , et plus).
Pour que TypeScript fonctionne avec les bases de code qui utilisent ces implémentations, il doit y avoir un type autre que Promise, sinon il y aurait beaucoup de contradictions.

34
Nitzan Tomer