TypeScript에서 infer
는 마치 마법 주문처럼 타입 추론의 범위를 넓혀줍니다.
덕분에 더욱 정확하고 유연한 타입을 정의할 수 있게 되었죠.
하지만 infer
는 늘 있었던 것은 아닙니다.
최근에 더욱 주목받는 이유는 무엇일까요?
infer를 이해하기 위한 여정: Conditional Type부터 시작
infer
를 처음 접했을 때, 저는 갑작스러운 등장에 당황했고, 제대로 활용하는 방법을 몰라 이해하는 데 시간이 걸렸습니다.
infer
를 제대로 이해하기 위해 먼저 Conditional Type에 대한 기본적인 내용을 복습했습니다.
아래 코드는 TypeScript 공식 문서에서 가져온 것입니다.
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
type Example1 = Dog extends Animal ? number : string;
type Example2 = RegExp extends Animal ? number : string;
이 삼항 연산자처럼 생긴 것이 바로 Conditional Type입니다.
Conditional Type:
T extends U ? X : Y
T extends U
는 T 타입이 U 타입의 서브타입(즉, U 타입에 할당 가능)인지 확인합니다.? X : Y
는T extends U
가 true이면 X 타입을 반환하고, 아니면 Y 타입을 반환합니다.
즉, T 타입이 U 타입에 포함되어 있으면 X 타입을 반환하고, 포함되어 있지 않으면 Y 타입을 반환합니다.
infer의 등장: 타입 추론의 진화
Conditional Type을 이해한 후, infer
에 대한 이해를 다시 시작했습니다.
Conditional Type:
T extends U ? X : Y
infer
는U
부분에서 사용하는 키워드입니다.
infer
는 TypeScript의 Conditional Type에서 사용되는 특수 키워드입니다.
Conditional Type은 특정 조건을 만족하는지 확인하고, 그 결과에 따라 다른 타입을 반환할 수 있는 기능입니다.
이는 프로그래밍의 if
문과 유사하지만, 타입에 대해 수행합니다.
infer
키워드는 Conditional Type 내에서 사용되며, 특정 타입에서 다른 타입을 "추론"(즉, 추출)하는 데 사용됩니다.
예를 들어, 함수의 반환 값 타입을 알고 싶을 때 infer
를 사용할 수 있습니다.
TypeScript 공식 문서의 코드를 다시 살펴보았습니다.
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
? Return
: never;
type Num = GetReturnType<() => number>;
type Str = GetReturnType<(x: string) => string>;
type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>;
확실히 U
부분이 (...args: never[]) => infer Return
으로 되어 있습니다.
위 코드는 Type
(T)가 "(인수를 받지 않는) 함수"인지 확인합니다.
Type
이 함수이면, 해당 함수의 반환 값 타입을 infer Return
으로 추출하여 Return
타입을 반환합니다.
Type
이 함수가 아니면 never
타입을 반환합니다.
참고로, 인수를 받는 함수의 경우 ...args: any[]
가 됩니다.
덧붙이자면, ...args
는 arguments
객체로 JavaScript에서도 사용됩니다.
https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/arguments
arguments
는 배열처럼(Array-like) 동작하는 객체로 함수에 전달된 인수 값을 포함하고 있으며, 함수 내에서 접근할 수 있습니다.
또 다른 샘플 코드를 살펴보았습니다.
다시 한번 TypeScript 공식 문서의 코드를 확인했습니다.
type Unpacked<T> = T extends (infer U)[]
? U
: T extends (...args: any[]) => infer U
? U
: T extends Promise<infer U>
? U
: T;
type T0 = Unpacked<string>; // string
type T1 = Unpacked<string[]>; // string
type T2 = Unpacked<() => string>; // string
type T3 = Unpacked<Promise<string>>; // string
type T4 = Unpacked<Promise<string>[]>; // Promise<string>
type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string
T extends (infer U)[]
T 타입이 배열 타입인지 확인합니다.
배열 타입이면 해당 배열의 요소 타입을 infer U
로 추출하고, U
타입을 반환합니다.
T extends (...args: any[]) => infer U
함수 타입인지 확인합니다.
T extends Promise
Promise 타입인지 확인합니다.
string
타입은 배열 타입도, 함수 타입도, Promise 타입도 아니기 때문에 그대로 타입을 반환합니다.
그래서 아래 코드는 string
을 반환합니다.
type T0 = Unpacked; // string
infer의 등장: 타입 추론의 새로운 지평을 열다
infer
는 TypeScript 2.8 버전에서 처음 등장했습니다.
이전에는 typeof
나 keyof
등으로 제한적인 타입 추론만 가능했지만, infer
는 제네릭 타입에서 특정 부분을 추론할 수 있도록 힘을 실어줍니다.
예를 들어, Promise
타입의 T
를 추론하는 경우를 살펴봅시다.
type PromiseType<T> = T extends Promise<infer U> ? U : never;
Promise<infer U>
를 통해 Promise
타입의 제네릭 파라미터 U
를 추론하여 PromiseType
을 정의할 수 있습니다.
infer를 활용한 다양한 패턴
infer
의 등장은 TypeScript 개발자들에게 새로운 가능성을 열어주었습니다.
- 조건부 타입을 활용한 다양한 타입 변환:
Promise
타입 뿐 아니라, 다양한 타입과 함께infer
를 사용하여 원하는 타입을 추출하고 변환할 수 있습니다. - 복잡한 타입 추론:
infer
를 활용하여 깊이 중첩된 객체의 타입을 추론하거나, 함수의 인자와 반환 값의 타입을 정확하게 추론할 수 있습니다. - 타입 안전성 향상:
infer
를 통해 타입 추론을 강화함으로써, 개발 중 발생할 수 있는 타입 오류를 미리 방지하고 코드의 안전성을 높일 수 있습니다.
infer와 함께 발전하는 TypeScript 생태계
infer
의 등장은 TypeScript 생태계에 큰 영향을 미쳤습니다.
- 타입 유틸리티 라이브러리의 발전:
infer
를 활용한 다양한 유틸리티 타입이 개발되어, 개발자들이 더욱 편리하게 타입 작업을 수행할 수 있도록 돕고 있습니다. - 더욱 강력해진 타입 정의:
infer
를 통해 더욱 정확하고 유연한 타입을 정의할 수 있게 되면서, TypeScript 코드의 가독성과 유지보수성이 향상되었습니다.
마무리
infer
는 TypeScript의 타입 추론 기능을 한 단계 끌어올린 핵심 기능입니다.
infer
를 활용하면 더욱 정확하고 안전한 TypeScript 코드를 작성할 수 있으며, TypeScript 생태계의 발전에도 크게 기여하고 있습니다.
infer
를 활용하여 타입 추론의 즐거움을 경험해 보세요!
'Javascript' 카테고리의 다른 글
JavaScript의 async, await에 대해 깊이 이해하기 (0) | 2024.07.01 |
---|---|
웹 개발의 핵심 개념들 : DOM과 가상 DOM, 모듈 번들러, 트랜스파일러, 바벨, 모듈, ESM, 비동기 처리, 그리고 프로미스 (0) | 2024.06.18 |
예제로 알아보는 TypeScript 유틸리티 타입 (1) | 2024.06.16 |
Deno v2를 향하여 - Deno v2, deno_std v1, Fresh v2에 대하여 (0) | 2024.06.10 |
PPR은 island 아키텍처인가? (0) | 2024.06.10 |