타입스크립트에서는 별걸 다 타입으로 만들 수 있다.
대표적으로 함수의 파라미터와 반환값의 타입을 얻어낼 수 있다.
export type ArgumentTypes<F extends (...a: any[]) => any> = F extends (
...args: infer A
) => any
? A
: never;
먼저 파라미터를 타입화 하면 위와 같다. 하나하나씩 자세히 설명하자면,
<F extends (...a: any[]) => any>
(...a: any[]) => any
를 만족하지 않는 것은 없기 때문에 그렇다. <F extends Function>
같은 방식도 가능하다.F extends (...args: infer A) => any ? A : never;
F
는 제네릭으로 입력 받은 함수이고, 그 함수가 (...args: infer A) => any
형태를 만족시켜야 한다. 이 말인즉슨, F
의 파라미터의 형태가 A
로 추론될 수 있어야 한다는 것이고, 곧 파라미터의 형태가 A
와 같아야 한다는 것이다. 이후 삼항연산자로 이어지지만 never
에 도달할 일은 없다.이걸 실제로 써보면 다음과 같이 된다.
function test(n: number, b: boolean): string {
return `${n}.${b}`;
}
const a: ArgumentTypes<typeof test> = [10, true];
test(...a);
함수의 타입들을 튜플 형태로 가져오게 되며, 그렇기에 전개연산자를 통해 함수에 파라미터로 줄 수도 있다.
또한 반환도 타입으로 지정할 수 있다.
export type ReturnType<F extends (...a: any[]) => any> = F extends (
...args: any[]
) => infer R
? R
: never;
아까의 ArgumentTypes
와의 차이점은 infer
의 위치뿐이다. 기존에는 파라미터 ...args
를 infer
로 지정했던 것이 이번에는 리턴 타입을 지정하는 부분(=> infer R
)으로 바뀌었다.
알아챘겠지만 리턴값이 R
과 동일해야 한다는 것을 의미한다. 마찬가지로 never
에는 도달할 일이 없다.
function test(n: number, b: boolean): string {
return `${n}.${b}`;
}
const r: ReturnType<typeof test> = "good";
위처럼 사용될 수 있다.
enum
도 타입화 할 수 있다.
export type Enum<E> = Record<keyof E, E[keyof E]>;
Record
는 {[key]: [value]}
형태의 오브젝트를 의미한다. 따라서 여기에서는 키 타입이 keyof E
이고 값 타입이 E[keyof E]
가 되는 것이다.
keyof E
라고 한다면 enum
의 키값들을 의미한다. 또한 E[keyof E]
는 제네릭으로 받은 E
라는 enum
에 대해 해당 키를 가지고서 얻은 값을 의미한다.
enum Status {
Pending = 0,
Done = 1,
}
위와 같은 간단한 enum
이 있다고 했을 때,
const a: Enum<Status> = Status.Done;
이런 식으로 이용이 가능하다.
이것들을 도대체 어디에 쓰냐고 물어볼 수 있는데 의외로 필요한 부분들이 가끔씩 생긴다.