Typescript의 Infer 키워드는 복잡한 타입에서 특정 부분을 추출하거나 추론할 때 사용하는 키워드이다.
Infer 키워드는 조건부 타입 내에서만 사용할 수 있고 Typescript 컴파일러가 타입을 자동으로 추론하게 한다.
먼저 조건부 타입에 대해 알아보고자 한다. 조건부 타입은 T extends U ? X : Y 형태로 타입을 조건에 따라 결정하는 기능이다.
내장 유틸 타입을 조건부 타입을 통해 구현할 수 있다.
type CustomExclude<T,U> = T extends U ? never : T;
type Result1 = CustomExclude<1 | 2 | 3 , 1>; // 2 | 3
type Result2 = CustomExclude<string | number | boolean , string>; // number | boolean
조건부 타입을 통해 T가 U를 포함할 경우 never 타입을, 포함하지 않을 경우 T를 반환한다.
예를 들어 1 | 2 | 3과 1을 넣을 경우 결과로 2 | 3이 나오게 된다.
여기서 조금 헷갈리는 부분이 있었는데, 1 | 2 | 3 extends 1 ? never : 1 | 2 | 3이 되는데 왜 never가 아닌 2 | 3이 나올까?
그 이유는 Union 타입이 T의 자리에 오게 되면 분산 조건부 타입이 적용되기 때문이다. 마치 수학에서 (1+2+3)*2를 하면 1*2+2*2+3*2가 되는 것 처럼 Union 타입에 있는 각각의 타입들에 대해 extends U ? never : T를 적용하는 것이다.
1 extends 1 ? never : 1 // never
2 extends 1 ? never : 2 // 2
3 extends 1 ? never : 3 // 3
Result1 = 2 | 3;
위와 같이 적용되어 CustomExclude<1 | 2 | 3 , 1>의 타입은 2 | 3이 되는 것이다.
type ExtractReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Result1 = ExtractReturnType<()=>string>; // string
type Result2 = ExtractReturnType<(x:number)=>boolean>; // boolean
위와 같이 infer를 사용한 유틸리티 타입 ExtractReturnType은 제네릭으로 입력받은 T 타입에서 리턴값을 추론한다.
여기서 중요한 점은 extends를 통해 T의 타입이 함수 형태인지를 먼저 확인한 다음 해당 함수에서 리턴 타입을 infer를 통해 추출한다는 것이다.
그 이유는 infer키워드는 타입의 구조 안에서 특정 부분을 추론하는데 이 타입의 구조를 알기 위해선 제네릭으로 입력된 타입 T의 구조를 먼저 extends를 통해 이러한 구조일 것이다 가정한 다음 그 안에서 부분적으로 타입을 추론하는 것이다.
만약 extends가 false일 경우엔 삼항 연산자의 :에 해당하는 타입을 반환한다.