为什么打字稿有一个类型,然后是“喜欢类型”?一个例子是Promise<T>
和PromiseLike<T>
。这两种类型有什么区别?我应该什么时候使用它们?在这种情况下,为什么不只有一个Promise
类型?
答案 0 :(得分:32)
如果你看一下定义文件(让我们来看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)
与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
的主要原因是在支持原生实体之前有几个实现可用(例如bluebird,Promises/A+,jQuery,更多)
为了使typescript能够使用那些使用这些实现的代码库,必须有一个Promise
以外的类型,否则会有很多矛盾。