Why does TypeScript use “Like” types?

后端 未结 1 817
故里飘歌
故里飘歌 2021-01-31 14:06

Why does TypeScript have a type and then a "like type"? An example of this is Promise and PromiseLike.

What are the

1条回答
  •  悲&欢浪女
    2021-01-31 14:34

    If you look at the definition files (let's take lib.es6.d.ts) then it's pretty straight forward.

    For example the ArrayLike interface:

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

    is more limited than the Array one:

    interface Array {
        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;
    }
    

    It's good to have the two separated because I might want to have a function like this:

    function getSize(arr: Array): number {
        return arr.length;
    }
    
    console.log(getSize([1, 2, 3])); // works
    

    But it won't work with this:

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

    It results with this error:

    Argument of type 'IArguments' is not assignable to parameter of type 'any[]'.
    Property 'push' is missing in type 'IArguments'.

    But both will work if I do this:

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

    (more on ArrayLike in MDN)

    The same with Promise and PromiseLike, if I'm building a library which isn't opinionated about the implementation of the Promise then instead of doing this:

    function doSomething(promise: Promise) { ... }
    

    I'll do this:

    function doSomething(promise: PromiseLike) { ... }
    

    Then even if the user of my library is using a different implementation (bluebird) it will work just fine.

    If you'll notice the definition of Promise is this:

    declare var Promise: PromiseConstructor;
    

    Which makes it very specific, other implementations might have different properties, for example a different prototype:

    interface PromiseConstructor {
        readonly prototype: Promise;
    
        ...
    }
    

    I guess that the main reason that we have PromiseLike is that several implementations were available before the native one was supported (such as bluebird, Promises/A+, jQuery, and more).
    In order for typescript to work with code bases that are using those implementations there must be a type other than Promise, otherwise there would be a lot of contradictions.

    0 讨论(0)
提交回复
热议问题