[TypeScript 독학] #12 타입스크립트 교과서(2)

안광의·2023년 11월 23일
0

TypeScript 독학

목록 보기
12/12
post-thumbnail

시작하며

『타입스크립트 교과서』의 후반부에는 자주 사용되는 패키지의 타입의 정의를 살펴보고 직접 타이핑해보는 과정이 담겨있다. 특정 패키지의 타입이나 직접 구현하는 내용보다는 그 과정에서 몰랐던 내용 위주로 정리하였다.

타입스크립트가 아닌 자바스크립트에 대한 내용은 소제목에 (js)라고 표기하였다.



instrinsic

instrinsic 타입은 내부적으로 따로 구현되어 있다는 뜻이다. ex) Uppercase


배열 메서드(js)

interface Array<T> {
  forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;
}

배열 메서드(forEach, map, reduce 등)의 두번째 인자로 this를 정할 수 있다.


Promise 객체 vs Promise 인스턴스(js)

Promise 객체Promise 인스턴스는 다른 개념이다.

Promise.resolve 에서의 PromisePromise 객체이고,
new Promise()Promise.resolve()의 반환 값이 Promise 인스턴스이다.


bind 타입

//v5.0.4
interface CallableFunction extends Function {
    ...
    bind<T, A0, A extends any[], R>(this: (this: T, arg0: A0, ...args: A) => R, thisArg: T, arg0: A0): (...args: A) => R;
    bind<T, A0, A1, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1): (...args: A) => R;
    bind<T, A0, A1, A2, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R;
    bind<T, A0, A1, A2, A3, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3): (...args: A) => R;
    bind<T, AX, R>(this: (this: T, ...args: AX[]) => R, thisArg: T, ...args: AX[]): (...args: AX[]) => R;
}
interface NewableFunction extends Function {
  	...
    bind<A0, A extends any[], R>(this: new (arg0: A0, ...args: A) => R, thisArg: any, arg0: A0): new (...args: A) => R;
    bind<A0, A1, A extends any[], R>(this: new (arg0: A0, arg1: A1, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1): new (...args: A) => R;
    bind<A0, A1, A2, A extends any[], R>(this: new (arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2): new (...args: A) => R;
    bind<A0, A1, A2, A3, A extends any[], R>(this: new (arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2, arg3: A3): new (...args: A) => R;
    bind<AX, R>(this: new (...args: AX[]) => R, thisArg: any, ...args: AX[]): new (...args: AX[]) => R;
}

bind의 인수 개수는 무한할 수 있기 때문에 인수 4개인 경우까지의 타입만 구현되어 있다.

//v5.1.6
interface CallableFunction extends Function {
  	...
    bind<T, A extends any[], B extends any[], R>(this: (this: T, ...args: [...A, ...B]) => R, thisArg: T, ...args: A): (...args: B) => R;
}
interface NewableFunction extends Function {
    ...
    bind<A extends any[], B extends any[], R>(this: new (...args: [...A, ...B]) => R, thisArg: any, ...args: A): new (...args: B) => R;
}

실제로 확인해보니 v5.1.6부터는 타입이 변경되어서 인수 개수가 많아져도 정확한 타입이 구현되도록 변경되었다.


tsc

타입스크립트는 타입스크립트 코드의 에러를 검사하는 작업과 타입스크립트 코드를 자바스크립트 코드로 변환하는 작업을 독립적으로 수행하기 때문에 타입에러와 관계없이 자바스크립트 변환작업은 수행된다.

$ npx tsc -noEmitOnError

에러가 없을 시에만 변환작업 수행하는 옵션


모듈의 타입을 구하는 순서

1. 현재 파일이 있는 폴더에 node_modules가 있는지 확인하고 있으면 2번부터 12번까지 순차적으로 파일을 찾을 때까지 수행, 없으면 부모 폴더로 올라가서 다시 1번을 수행
2. node_modules/module.ts
3. node_modules/module.tsx
4. node_modules/module.d.ts
5. node_modules/module/package.json 속성 찾기
6. node_modules/module/index.ts
7. node_modules/module/index.tsx
8. node_modules/module/index.d.ts
9. node_modules/@types/module/package.json 속성 찾기
10. node_modules/@types/module.d.ts
11. node_modules/@types/module/index.d.ts
12. 2~11번까지 모두 못찾았으면 부모 폴더로 올라가서 1번을 수행
13. 최상위 폴더까지 갔는데도 못 찾으면 에러

declare global

declare global는 모듈 파일 안에서 전역 타입을 만드는 선언 방식이다.


declare module

declare module는 타입스크립트에게 해당 모듈이 있다는 걸 알리고, 해당 모듈에 대한 타입 선언도 이 블록 안에 있음을 알리는 선언이다.


같은 폴더 내의 d.ts

같은 이름의 ts 파일과 d.ts 파일이 같은 폴더에 존재하면 타입스크립트는 ts 파일만 인식한다.


패키지 타입 직접 타이핑하기

직접 패키지를 타이핑할때 declare module 내부에 있는 importdeclare module 외부로 빼면 안된다.
=> 기존 모듈을 새로 선언하게 되므로

declare module을 사용하지 않고 tsconfig.jsonbaseUrlpaths 옵션으로 타입의 경로를 지정하는 방법도 있다.


패키지 만들기

tsconfig.jsonrootDir의 기본값은 tsconfig.json이 위치한 경로가 아니고 ts 파일(d.ts 파일은 무시)이 위치한 가장 얕은 경로이다.

마치며

책의 후반부에는 타입을 찾아서 이해하는 과정과 에러가 발생하지 않도록 직접 타입을 구현하는 방법에 대한 이해가 필요한 파트여서 정리할 내용이 많지 않았다. 이미 구현되어 있는 패키지의 타입을 이해하고 어떤 방법으로 정의되어 있는지 보는 것이 실무에서 타입 정의를 하는데 도움이 된다고 느꼈다.

profile
개발자로 성장하기

0개의 댓글