TypeScript 미드레벨 프레임워크 심화 면접
새 면접Q. TypeScript의 infer 키워드의 동작 원리를 설명하고, ReturnType이나 Parameters 같은 내장 유틸리티 타입이 infer를 어떻게 활용하는지 설명해주세요. 또한 실무에서 복잡한 타입 추론이 필요한 경우(예: 함수 체이닝의 반환 타입 추론) infer를 활용한 커스텀 유틸리티 타입 작성 전략을 설명해주세요.
infer는 conditional type 내에서 타입을 추론하고 캡처하는 키워드입니다. ReturnType<T>는 'T extends (...args: any) => infer R ? R : any' 형태로 함수의 반환 타입을 추출합니다. Parameters<T>는 'T extends (...args: infer P) => any ? P : never'로 매개변수 튜플 타입을 추출합니다. 실무에서는 Promise<infer U>로 비동기 함수의 resolve 타입을 추출하거나, 중첩된 배열 타입을 평탄화하는 DeepFlatten 같은 재귀적 유틸리티 타입을 작성할 때 활용합니다. 함수 체이닝에서는 각 메서드의 반환 타입을 infer로 추론하여 타입 안정성을 유지하면서도 유연한 API를 설계할 수 있습니다.
- • infer는 conditional type 내에서만 사용 가능하며 타입을 추론하고 변수처럼 캡처함
- • ReturnType과 Parameters는 함수 타입에서 특정 부분을 추출하기 위해 infer를 활용
- • 실무에서는 Promise unwrapping, 재귀적 타입 변환, 함수 체이닝 타입 추론에 활용
- • infer를 여러 번 사용하여 복잡한 제네릭 타입에서 여러 부분을 동시에 추출 가능
infer를 사용한 타입 추론이 실패하는 경우(예: 타입이 조건을 만족하지 않을 때)의 처리 전략과, covariant와 contravariant 위치에서 infer를 사용할 때의 차이점을 설명해주세요.
Q. TypeScript에서 Branded Type(또는 Opaque Type) 패턴이 무엇인지 설명하고, 이를 사용하여 런타임에는 같은 타입이지만 컴파일 타임에는 다른 타입으로 취급되는 UserId와 ProductId를 구분하는 방법을 설명해주세요. 이 패턴이 타입 안정성을 높이는 실무 시나리오도 함께 설명해주세요.
Branded Type은 primitive 타입에 고유한 브랜드를 추가하여 구조적으로는 같지만 명목적으로 다른 타입을 만드는 패턴입니다. 'type UserId = string & { readonly brand: unique symbol }'처럼 intersection type과 unique symbol을 사용하여 구현합니다. 런타임에는 일반 string이지만 컴파일 타임에는 UserId와 ProductId를 구분하여 잘못된 ID 타입 전달을 방지합니다. 실무에서는 금액(원화/달러), 길이 단위(미터/피트), 인코딩된 문자열(base64/url-encoded) 등을 구분하여 타입 안정성을 높이고, 함수 인자 순서 실수나 잘못된 값 할당을 컴파일 단계에서 방지합니다.
- • intersection type과 unique symbol을 사용하여 구조적으로는 같지만 명목적으로 다른 타입 생성
- • 런타임 오버헤드 없이 컴파일 타임 타입 안정성 확보
- • ID, 단위, 인코딩 등 의미적으로 다른 값을 타입 레벨에서 구분
- • 타입 가드 함수나 팩토리 함수를 통해 브랜드 타입 생성 및 검증
Branded Type을 사용할 때 JSON 직렬화/역직렬화나 외부 API 응답을 처리하는 과정에서 발생할 수 있는 문제점과 이를 해결하기 위한 validation 전략을 설명해주세요.
Q. TypeScript의 Declaration Merging(선언 병합) 기능이 무엇인지 설명하고, interface와 namespace가 병합되는 규칙을 설명해주세요. 또한 실무에서 외부 라이브러리의 타입을 확장할 때(예: Express의 Request 객체에 user 속성 추가) Declaration Merging을 활용하는 방법과 주의사항을 설명해주세요.
Declaration Merging은 같은 이름의 선언이 여러 번 나타날 때 컴파일러가 이들을 하나로 병합하는 기능입니다. interface는 같은 이름으로 여러 번 선언하면 모든 멤버가 병합되며, namespace도 같은 이름으로 선언 시 병합됩니다. Express의 Request 타입 확장은 'declare global { namespace Express { interface Request { user?: User } } }' 형태로 ambient module declaration을 사용합니다. 주의사항으로는 병합 순서에 따라 오버로드 우선순위가 달라지고, 같은 이름의 속성을 다른 타입으로 선언하면 에러가 발생하며, d.ts 파일의 위치와 tsconfig의 typeRoots 설정이 중요합니다.
- • interface, namespace, enum 등은 같은 이름으로 여러 번 선언 시 자동으로 병합됨
- • 외부 라이브러리 타입 확장 시 declare global과 ambient module declaration 활용
- • 병합 시 같은 속성을 다른 타입으로 선언하면 컴파일 에러 발생
- • d.ts 파일 위치와 tsconfig 설정이 타입 병합 인식에 중요
Declaration Merging과 Module Augmentation의 차이점을 설명하고, monorepo 환경에서 여러 패키지가 같은 외부 라이브러리 타입을 각각 확장할 때 발생할 수 있는 타입 충돌 문제와 해결 방법을 설명해주세요.
Q. TypeScript 컴파일 속도가 느려지는 주요 원인들을 설명하고, 대규모 프로젝트에서 컴파일 성능을 개선하기 위한 전략(Project References, incremental compilation, skipLibCheck 등)을 설명해주세요. 또한 복잡한 타입 연산이 컴파일 성능에 미치는 영향과 최적화 방법도 함께 설명해주세요.
컴파일 속도 저하의 주요 원인은 과도한 타입 추론, 복잡한 conditional type, 거대한 union type, 그리고 모든 d.ts 파일의 검사입니다. Project References는 프로젝트를 여러 하위 프로젝트로 분할하여 병렬 빌드와 선택적 재컴파일을 가능하게 합니다. incremental compilation은 tsBuildInfoFile을 생성하여 변경된 파일만 재컴파일하고, skipLibCheck는 node_modules의 타입 정의 파일 검사를 건너뛰어 속도를 향상시킵니다. 복잡한 타입 연산은 재귀 깊이 제한이나 instantiation depth exceeded 에러를 유발하므로, 타입을 단순화하거나 명시적 타입 어노테이션으로 추론 범위를 제한해야 합니다.
- • Project References로 모노레포를 여러 하위 프로젝트로 분할하여 병렬 빌드 및 선택적 재컴파일
- • incremental: true와 tsBuildInfoFile로 변경된 파일만 재컴파일
- • skipLibCheck로 외부 라이브러리 타입 정의 검사 건너뛰기
- • 복잡한 재귀 타입이나 거대한 union type은 명시적 타입 어노테이션으로 추론 범위 제한
TypeScript 4.x 이후 추가된 performance tracing 기능을 활용하여 컴파일 병목 지점을 찾는 방법과, 타입 체크와 트랜스파일을 분리하는 전략(예: babel과 tsc의 역할 분담)의 장단점을 설명해주세요.
Q. TypeScript에서 Variadic Tuple Types의 개념과 동작 원리를 설명하고, 이를 활용하여 가변 인자 함수의 타입을 안전하게 정의하는 방법을 설명해주세요. 특히 함수 합성(compose)이나 파이프(pipe) 함수를 구현할 때 각 함수의 입출력 타입을 연결하는 방법과 실무에서의 활용 사례를 설명해주세요.
Variadic Tuple Types는 TypeScript 4.0에서 도입된 기능으로, 제네릭 타입 매개변수를 튜플의 나머지 요소로 사용할 수 있게 합니다. '...T extends any[]' 형태로 선언하며, 여러 튜플을 연결하거나 분산할 수 있습니다. 함수 합성에서는 'type Pipe<F extends Function[], T = never> = ...' 형태로 각 함수의 반환 타입이 다음 함수의 입력 타입과 일치하는지 검증합니다. 실무에서는 Redux middleware 체인, Express middleware 타입 정의, React HOC 합성 등에서 타입 안정성을 유지하면서 가변 개수의 함수를 안전하게 조합할 수 있습니다. 또한 curry 함수나 partial application의 타입 정의에도 활용됩니다.
- • Variadic Tuple Types로 가변 길이 튜플을 제네릭 타입 매개변수로 처리
- • 함수 합성에서 각 함수의 입출력 타입을 연쇄적으로 검증 가능
- • middleware 체인, HOC 합성, curry 함수 등에서 타입 안정성 확보
- • 튜플의 spread 연산자와 결합하여 복잡한 타입 변환 구현
Variadic Tuple Types를 사용할 때 발생할 수 있는 타입 추론의 한계(예: 튜플 길이가 너무 길 때)와, 이를 극복하기 위한 overload signature 활용 전략을 설명해주세요. 또한 named tuple elements와의 결합 방법도 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!