infer 키워드를 사용한 조건부 타입은 복잡한 데이터 타입에서 타입을 추출할 수 있게 해줍니다. 고전적인 예로, 배열에서 요소 타입을 추출하는 것이 있습니다:
type ElementType<T> = T extends (infer U)[] ? U : T;
여기서 infer U는 배열 T의 요소 타입을 계산할 수 있게 해줍니다. 만약 T가 배열이라면, 그 요소의 타입이 반환되고, 그렇지 않으면 T 자체가 반환됩니다.
사용되는 곳:
예:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
하나의 조건부 타입에서 여러 개의 infer를 사용할 수 있나요? 이 경우 TypeScript는 어떻게 해석하나요?
잘못된 답변:
올바른 답변:
type FirstArgument<T> = T extends (infer F, ...any[]) => any ? F : never; // 하지만 함수와 관련해서는 더 정확합니다: type Args<T> = T extends (...args: infer A) => any ? A : never;
이야기
개발자가 함수가 반환하는 객체의 타입을 얻는 방법을 작성했지만, 함수가 Promise를 반환할 수 있다는 것을 고려하지 않았습니다. 결과적으로 반환값의 타입은 항상 Promise<any>였으며, 중첩된 conditional 타입을 사용하지 않았기 때문에 모든 코드베이스에서 리팩토링해야 했습니다.
이야기
프로젝트에서 중첩 배열을 풀기 위한 일반 타입을 도입했지만, 조건의 최종 else-branch를 작성하는 것을 잊었습니다. TypeScript는 정확하게 오류를 발생시키지 않았지만, 몇 가지 경우에 사용 시 결과가 never가 되어 외부 라이브러리의 일부 유틸리티 타입화가 깨지는 문제가 발생했습니다.
이야기
동료가 combine-conditional/infer 타입을 통해 큰 인터페이스의 속성 타입을 추출하려 했으나, 일부 속성이 자체적으로 union 타입인 것을 고려하지 않았습니다. 그 결과 예상치 못한 union 타입 조합이 출력되어, 컴파일러는 통과했지만 로직이 잘못 작동하는 문제가 발생했습니다.