jaenny.dev

타입스크립트에는 -Like 타입이 있다. ArrayArrayLike, PromisePromiseLike

-Like postFix가 붙여진 타입이 왜 필요한지 알아보자.

 

Array vs. ArrayLike

Array

lib.es2015.core.ts 파일에서는 Array 타입을 다음과 같이 정의하고 있다. 자주 사용하는 find, fill 등의 메소드도 찾아볼 수 있다.

interface Array<T> {
    /**
     * Returns the value of the first element in the array where predicate is true, and undefined
     * otherwise.
     * @param predicate find calls predicate once for each element of the array, in ascending
     * order, until it finds one where predicate returns true. If such an element is found, find
     * immediately returns that element value. Otherwise, find returns undefined.
     * @param thisArg If provided, it will be used as the this value for each invocation of
     * predicate. If it is not provided, undefined is used instead.
     */
    find<S extends T>(predicate: (this: void, value: T, index: number, obj: T[]) => value is S, thisArg?: any): S | undefined;
    find(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): T | undefined;

    /**
     * Returns the index of the first element in the array where predicate is true, and -1
     * otherwise.
     * @param predicate find calls predicate once for each element of the array, in ascending
     * order, until it finds one where predicate returns true. If such an element is found,
     * findIndex immediately returns that element index. Otherwise, findIndex returns -1.
     * @param thisArg If provided, it will be used as the this value for each invocation of
     * predicate. If it is not provided, undefined is used instead.
     */
    findIndex(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): number;

    /**
     * Changes all array elements from `start` to `end` index to a static `value` and returns the modified array
     * @param value value to fill array section with
     * @param start index to start filling the array at. If start is negative, it is treated as
     * length+start where length is the length of the array.
     * @param end index to stop filling the array at. If end is negative, it is treated as
     * length+end.
     */
    fill(value: T, start?: number, end?: number): this;

    /**
     * Returns the this object after copying a section of the array identified by start and end
     * to the same array starting at position target
     * @param target If target is negative, it is treated as length+target where length is the
     * length of the array.
     * @param start If start is negative, it is treated as length+start. If end is negative, it
     * is treated as length+end.
     * @param end If not specified, length of the this object is used as its default value.
     */
    copyWithin(target: number, start: number, end?: number): this;
}

ArrayLike

반면 lib.es5.d.ts 파일에서는 배열 길이 반환과 인덱스 기반 접근만 가능하다고 심플하게 ArrayLike를 정의하고 있다.

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

✅ 차이점

자바스크립트 언어에서는 배열과 유사하지만, 완벽한 배열은 아닌 유사 배열 객체가 존재한다.

대표적으로 다음과 같은 상황에서 사용된다.

조금 더 넓은 의미로 배열 타입을 사용하여 유사 배열 객체까지 포함하는 타입이 필요하기 때문에 ArrayLike를 추가했다고 볼 수 있다.

 

 

 

Promise vs. PromiseLike

Promise

Promise에는 나중에 finally가 추가되어서 두 개의 파일을 살펴보아야 한다.

lib.es5.d.ts에는 thencatch가 정리되어 있다.

/**
 * Represents the completion of an asynchronous operation
 */
interface Promise<T> {
    /**
     * Attaches callbacks for the resolution and/or rejection of the Promise.
     * @param onfulfilled The callback to execute when the Promise is resolved.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of which ever callback is executed.
     */
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

    /**
     * Attaches a callback for only the rejection of the Promise.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of the callback.
     */
    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}

lib.es2018.promise.d.ts에서는 finally가 추가되었다.

/**
 * Represents the completion of an asynchronous operation
 */
interface Promise<T> {
    /**
     * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
     * resolved value cannot be modified from the callback.
     * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).
     * @returns A Promise for the completion of the callback.
     */
    finally(onfinally?: (() => void) | undefined | null): Promise<T>
}

PromiseLike

그런데 lib.es5.d.tsPromiseLike를 보면 then만 정의되어있다.

interface PromiseLike<T> {
    /**
     * Attaches callbacks for the resolution and/or rejection of the Promise.
     * @param onfulfilled The callback to execute when the Promise is resolved.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of which ever callback is executed.
     */
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;
}

✅ 차이점

PromiseLike 역시 ArrayLike와 비슷하게 넓은 의미의 타입 적용을 가능하게 하려고 만든 타입이다.

처음 Promise 개념이 등장했을 때는 then만 지원하는 라이브러리가 많았다고 한다. (bluebird, Promises/A+, jQuery 등등...)

그럴 수 밖에 없는게 then밖에 없었음😇

 

하지만 개발자의 필요에 의해 catchfinally가 정식 문법으로 추가되면서
Promise 타입은 정식 문법에 맞추어 then, catch, finally를 모두 지원하는 타입으로,
PromiseLike는 과거 라이브러리들과의 호환성에 맞추어 then만 지원하는 타입도 포함하도록 정의되었다고 볼 수 있다.

 

 

 

 

참고한 링크

profile

jaenny.dev

@jaenny.dev

Go Beyond! Front-end developer, jaenny✨