TypeScript 시니어 프레임워크 면접

TypeScript 시니어 (7년+) 프레임워크 5문항 조회수 114 · 2026-06-19 (금) 19:11:03
1 TypeScript Compiler API
Hard

Q. TypeScript의 컴파일 과정은 Scanner → Parser → Binder → Checker → Emitter 단계로 이루어집니다. 각 단계의 역할을 설명하고, TypeScript Compiler API를 활용하여 커스텀 코드 변환 도구(예: 자동 API 클라이언트 생성기)를 구현할 때 어떤 단계에서 AST를 조작해야 하는지, 그리고 타입 정보를 보존하면서 안전하게 코드 변환을 수행하는 방법을 설명해주세요.

A. 모범답안

Scanner는 소스 코드를 토큰으로 분리하고, Parser는 토큰을 AST(Abstract Syntax Tree)로 변환합니다. Binder는 심볼과 스코프를 생성하여 선언과 참조를 연결하고, Checker는 타입 검사를 수행하며, Emitter는 JavaScript 코드를 생성합니다. 커스텀 변환 도구는 주로 Transformer API를 사용하여 Checker 이후 Emitter 이전 단계에서 AST를 조작해야 하며, ts.TransformerFactory를 통해 타입 정보에 접근하면서 안전한 변환을 수행할 수 있습니다. ts.TypeChecker를 활용하면 노드의 타입 정보를 쿼리하여 타입 기반 코드 생성이 가능합니다.

핵심 포인트
  • • 5단계 컴파일 파이프라인: Scanner(토큰화) → Parser(AST 생성) → Binder(심볼 바인딩) → Checker(타입 검사) → Emitter(JS 생성)
  • • 커스텀 변환은 ts.TransformerFactory를 사용하여 Checker 이후 단계에서 AST 조작
  • • ts.TypeChecker API로 노드의 타입 정보 쿼리 및 타입 안전한 코드 변환 구현
  • • ts.createSourceFile, ts.visitEachChild 등으로 AST 순회 및 변환
Follow-up 질문

TypeScript Compiler API를 사용할 때 메모리 사용량이 급격히 증가하는 문제를 경험한 적이 있나요? Program 인스턴스의 재사용과 증분 컴파일을 통해 성능을 최적화하는 방법을 설명해주세요.

2 Advanced Type System
Hard

Q. TypeScript의 구조적 타이핑(Structural Typing)과 명목적 타이핑(Nominal Typing)의 차이를 설명하고, TypeScript에서 구조적 타이핑으로 인해 발생할 수 있는 문제점을 설명해주세요. 또한 Brand 타입 패턴을 활용하여 명목적 타이핑을 시뮬레이션하여 타입 안정성을 높이는 방법과, 이를 활용한 실무 사례(예: UserId와 ProductId 구분)를 포함해주세요.

A. 모범답안

구조적 타이핑은 타입의 구조(프로퍼티와 메서드)가 같으면 호환되는 방식이고, 명목적 타이핑은 타입의 이름이 같아야 호환되는 방식입니다. TypeScript는 구조적 타이핑을 사용하여 { id: string } 타입을 가진 UserId와 ProductId가 서로 호환되는 문제가 발생할 수 있습니다. Brand 타입은 type UserId = string & { readonly brand: unique symbol } 형태로 고유한 심볼을 추가하여 구조적으로 다른 타입을 만들어 명목적 타이핑을 시뮬레이션합니다. 이를 통해 함수 파라미터에서 잘못된 ID 타입 전달을 컴파일 타임에 방지할 수 있습니다.

핵심 포인트
  • • 구조적 타이핑: 구조가 같으면 호환, 명목적 타이핑: 이름이 같아야 호환
  • • TypeScript는 구조적 타이핑으로 인해 의미적으로 다른 타입이 호환되는 문제 발생 가능
  • • Brand 타입 패턴: unique symbol을 사용한 교차 타입으로 명목적 타이핑 시뮬레이션
  • • 실무에서 ID, 화폐 단위, 측정 단위 등 도메인 타입 구분에 활용
Follow-up 질문

Brand 타입을 사용할 때 런타임 검증 없이 타입 단언만으로 값을 생성하면 타입 안정성이 깨질 수 있습니다. Smart Constructor 패턴을 결합하여 런타임 검증과 타입 안정성을 모두 보장하는 방법을 설명해주세요.

3 TypeScript Module System
Medium

Q. TypeScript의 모듈 해석 전략인 Classic과 Node 방식의 차이를 설명하고, moduleResolution, baseUrl, paths 옵션이 모듈 해석에 미치는 영향을 설명해주세요. 특히 모노레포 환경에서 여러 패키지 간 타입 공유 시 발생할 수 있는 모듈 해석 문제와 해결 방법, 그리고 Project References를 활용한 빌드 최적화 전략을 포함해주세요.

A. 모범답안

Classic 방식은 상대 경로부터 상위 디렉토리로 올라가며 모듈을 찾고, Node 방식은 node_modules를 포함하여 Node.js와 동일한 해석 전략을 사용합니다. baseUrl은 절대 경로 import의 기준점을 설정하고, paths는 경로 별칭을 매핑합니다. 모노레포에서는 패키지 간 의존성 해석 시 심볼릭 링크나 paths 설정이 필요하며, Project References(tsconfig.json의 references 필드)를 사용하면 패키지 간 의존성을 명시하여 증분 빌드와 병렬 빌드가 가능해져 빌드 시간을 크게 단축할 수 있습니다.

핵심 포인트
  • • Classic: 상대 경로 기반 해석, Node: node_modules 포함 Node.js 방식 해석
  • • baseUrl(기준 경로), paths(경로 별칭)로 모듈 해석 커스터마이징
  • • 모노레포에서 패키지 간 타입 공유 시 paths 설정 또는 심볼릭 링크 활용
  • • Project References로 패키지 의존성 명시 및 증분/병렬 빌드 최적화
Follow-up 질문

TypeScript 4.7+에서 도입된 Node16/NodeNext moduleResolution이 기존 Node 방식과 어떻게 다른지, 그리고 package.json의 exports 필드를 활용한 서브패스 매핑을 TypeScript에서 어떻게 지원하는지 설명해주세요.

4 Conditional Types & Type Inference
Hard

Q. TypeScript의 Conditional Types에서 infer 키워드의 동작 원리를 설명하고, 이를 활용하여 함수의 반환 타입, Promise의 래핑된 타입, 배열의 요소 타입을 추출하는 유틸리티 타입을 설계하는 방법을 설명해주세요. 또한 재귀적 Conditional Types를 사용하여 깊은 중첩 구조의 타입 변환(예: DeepReadonly, DeepPartial)을 구현할 때의 제약사항과 TypeScript 4.5+의 Tail Recursion Optimization을 포함해주세요.

A. 모범답안

infer 키워드는 Conditional Types의 extends 절에서 타입의 일부를 변수로 캡처하여 추출할 수 있게 합니다. type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never 형태로 함수 반환 타입을 추출하고, type Unwrap<T> = T extends Promise<infer U> ? U : T로 Promise 타입을 언래핑합니다. 재귀적 Conditional Types는 type DeepReadonly<T> = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K] } 형태로 구현하지만, 순환 참조 타입에서는 제한이 있습니다. TypeScript 4.5+는 꼬리 재귀 최적화로 재귀 깊이 제한을 완화했습니다.

핵심 포인트
  • • infer 키워드: Conditional Types에서 타입 패턴 매칭 및 부분 타입 추출
  • • 함수 반환 타입, Promise 언래핑, 배열 요소 타입 추출 등에 활용
  • • 재귀적 Conditional Types로 DeepReadonly, DeepPartial 같은 깊은 타입 변환 구현
  • • TypeScript 4.5+ 꼬리 재귀 최적화로 재귀 깊이 제한 완화, 순환 참조는 여전히 제약
Follow-up 질문

Distributive Conditional Types의 동작 원리를 설명하고, Union 타입이 Conditional Types를 만났을 때 분배 법칙이 적용되는 이유와, 이를 방지하기 위해 튜플로 래핑하는 기법을 설명해주세요.

5 Declaration Merging & Ambient Declarations
Medium

Q. TypeScript의 Declaration Merging 메커니즘을 설명하고, 인터페이스, 네임스페이스, 모듈의 선언 병합 규칙을 설명해주세요. 특히 서드파티 라이브러리의 타입 정의를 확장할 때 declare global과 declare module을 활용하는 방법과, Express Request 객체에 커스텀 프로퍼티를 추가하는 실무 사례를 포함해주세요. 또한 .d.ts 파일의 역할과 ambient declaration의 특징도 설명해주세요.

A. 모범답안

Declaration Merging은 같은 이름의 선언을 하나로 병합하는 메커니즘으로, 인터페이스는 프로퍼티가 병합되고, 네임스페이스는 export된 멤버가 병합되며, 모듈은 augmentation을 통해 확장됩니다. declare global { ... }은 전역 스코프를 확장하고, declare module 'express-serve-static-core' { interface Request { user?: User } }는 Express Request를 확장합니다. .d.ts 파일은 타입 선언만 포함하며 런타임 코드를 생성하지 않는 ambient declaration 파일로, 기존 JavaScript 라이브러리에 타입을 추가하거나 전역 타입을 선언할 때 사용됩니다.

핵심 포인트
  • • Declaration Merging: 같은 이름의 인터페이스, 네임스페이스, 모듈 선언 자동 병합
  • • 인터페이스는 프로퍼티 병합, 네임스페이스는 export 멤버 병합, 모듈은 augmentation
  • • declare global로 전역 스코프 확장, declare module로 기존 모듈 타입 확장
  • • .d.ts 파일은 ambient declaration으로 런타임 코드 없이 타입만 선언
Follow-up 질문

여러 개발자가 동일한 인터페이스를 독립적으로 확장하는 모노레포 환경에서 Declaration Merging으로 인한 타입 충돌 문제를 어떻게 방지하고 관리하시겠습니까? 네임스페이스 전략과 타입 가드 활용 방안을 포함해주세요.

댓글 0

로그인 후 댓글을 작성할 수 있습니다.

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!