Почему машинописный шрифт имеет тип, а затем "похожий тип"? Примером этого может служить Promise<T>
и PromiseLike<T>
. Каковы различия между этими двумя типами? Когда я должен их использовать? В этом случае, почему бы просто не использовать один тип Promise
?
Почему типы типов используют типы "Like"?
Ответ 1
Если вы посмотрите на файлы определения (пусть возьмите 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;
}
Хорошо иметь два разделенных, потому что я мог бы иметь такую функцию:
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 []".
Свойство "push" отсутствует в типе "IArguments".
Но оба будут работать, если я это сделаю:
function getSize(arr: ArrayLike<any>): number {
return arr.length;
}
(больше на ArrayLike в MDN)
То же самое с Promise
и PromiseLike
, если я создаю библиотеку, которая не усомнилась в реализации Promise
вместо этого:
function doSomething(promise: Promise<any>) { ... }
Я сделаю это:
function doSomething(promise: PromiseLike<any>) { ... }
Тогда даже если пользователь моей библиотеки использует другую реализацию (bluebird), она будет работать нормально.
Если вы заметите, что определение Promise заключается в следующем:
declare var Promise: PromiseConstructor;
Это делает его очень специфичным, другие реализации могут иметь разные свойства, например, другой прототип:
interface PromiseConstructor {
readonly prototype: Promise<any>;
...
}
Я думаю, что главная причина того, что мы имеем PromiseLike
что несколько реализаций были доступны прежде, чем нативный один был поддержан (например, Блюберд, Promises/A+, JQuery, и многое другое).
Для того, чтобы машинопись работала с базами кода, использующими эти реализации, должен существовать тип, отличный от Promise
, иначе было бы много противоречий.