프로그래밍TypeScript 아키텍트

TypeScript에서 조건부 타입(conditional types)은 어떻게 작동하나요? 조건부 타입의 배급적 행동(distrbutive behavior)은 무엇이며, 이를 어떻게 다루나요? 예제와 함께 설명해 주세요.

Hintsage AI 어시스턴트로 면접 통과

답변.

TypeScript의 조건부 타입(Conditional Types)은 T extends U ? X : Y 원리에 따라 하나의 타입을 다른 타입으로 설명할 수 있게 해줍니다. 이러한 타입은 복잡한 타입 논리를 구축할 때 강력한 가능성을 제공하며, 특히 라이브러리 및 API 선언에서 유용합니다.

기본 조건부 타입 예시:

type IsString<T> = T extends string ? 'yes' : 'no'; type A = IsString<string>; // 'yes' type B = IsString<number>; // 'no'

배급적 행동

조건부 타입이 유니온 타입에 적용되면 TypeScript는 조건을 각 유니온의 요소에 개별적으로 ‘분배’합니다. 이를 조건부 타입의 배급적 행동이라고 부릅니다.

예제:

type Foo<T> = T extends { id: number } ? string : boolean; type Result = Foo<{id: number} | {name: string}>; // string | boolean

이것은 매우 강력한 기능이지만, 특히 배열 및 타입 매핑을 다룰 때 예상되는 결과와의 혼란을 야기할 수 있습니다.

배급적 행동 피하는 방법

타입을 튜플로 감싸기:

type NoDistrib<T> = [T] extends [{id: number}] ? string : boolean; type Result = NoDistrib<{id: number} | {name: string}>; // boolean

트릭질문.

질문: "유니온 타입과 함께 조건부 타입을 사용할 때, 튜플로 감싸지 않으면 어떤 일이 발생하나요? 결과가 항상 일반적인 논리와 동일한가요?"

답변: 결과는 예기치 않게 나올 수 있습니다! 배급성 때문에 조건이 각 유니온 타입의 구성원에 개별적으로 적용됩니다. 전체 유니온 타입을 엄격하게 비교하려면 래퍼(튜플)를 사용해야 합니다.

예제:

type Test<T> = T extends string ? number : boolean; type A = Test<string | boolean>; // number | boolean, 단순히 boolean이 아님

주제에 대한 미세한 차이로 인한 실제 오류 예제.


이야기

직렬화 라이브러리에서 데이터 구조를 확인하기 위해 조건부 타입을 사용했지만 제너릭 매개변수를 튜플로 감싸는 것을 잊었습니다. 결과적으로 복잡한 유니온 타입의 선언이 깨지고, 컴파일러는 API 사용 시 예측할 수 없는 타입을 생성했습니다.


이야기

모델 필드를 처리하기 위한 타입 변형을 구현하려 할 때, 배급성 때문에 일부 정보가 손실되었습니다. 배급성으로 인해 유니온이 생성되면서 몇 가지 로직 분기가 처리되지 않았고 결국 타이핑이 지나치게 허용적으로 되었습니다.


이야기

개발자는 T extends SomeType이 조건부 타입 내에서 전체 객체에 대해 우리가 기대하는 대로 작동할 것이라고 생각했지만, "분산"이 발생했습니다. 컴파일러는 불일치를 지적했고, 타입 혼란과 자동 문서화의 심각한 버그가 발생했습니다.