패스잇

프론트엔드 개발

TypeScript 면접 질문

타입 시스템, 제네릭, 유틸리티 타입, 구조적 타이핑 — TypeScript 면접은 "타입을 왜, 어떻게 쓰는가"를 묻습니다. JavaScript와의 차이를 넘어 타입을 안전하게 설계하는 사고를 보여 줄 수 있도록 정리했습니다.

총 21문제 · 기초 7 · 중급 7 · 심화 7 · 모범답안 포함

TypeScript 면접 질문 — 기초

Q1 기초

TypeScript란 무엇이며, JavaScript와 비교했을 때 어떤 주요 장점을 가지나요?

힌트 · 정적 타입 언어로서 코드 안정성, 유지보수성, 개발 생산성 향상에 기여합니다.

TypeScript는 JavaScript에 타입을 더한 언어입니다. JavaScript의 모든 기능을 포함하면서, 정적 타입을 지원하여 코드의 안정성을 높여줍니다.

전체 모범답안 펼치기

TypeScript는 JavaScript에 타입을 더한 언어입니다. JavaScript의 모든 기능을 포함하면서, 정적 타입을 지원하여 코드의 안정성을 높여줍니다.

JavaScript와 비교했을 때 주요 장점은 다음과 같습니다.

  • 코드 안정성: 컴파일 시점에 타입 에러를 잡아내어 런타임 에러를 줄여줍니다.
  • 유지보수성: 코드의 의도를 명확하게 표현하여 가독성을 높이고, 리팩토링을 용이하게 합니다.
  • 개발 생산성: 자동 완성, 타입 검사 등의 기능을 통해 개발 속도를 향상시켜 줍니다. 타입 추론 덕분에 모든 변수에 타입을 명시할 필요는 없습니다.

또한, TypeScript는 점진적으로 도입할 수 있다는 장점이 있습니다. 기존 JavaScript 프로젝트에 TypeScript를 조금씩 적용해 나갈 수 있습니다.

#정적 타입#타입 추론#코드 예측성#리팩토링#점진적 도입

이 질문 단독 페이지 →

Q2 기초

TypeScript에서 변수에 타입을 명시하는 '타입 주석(Type Annotation)'은 무엇이며, 언제 주로 사용하나요?

힌트 · 변수, 함수 매개변수, 반환 값 등에 개발자가 직접 타입을 지정하여 코드의 의도를 명확히 하고 오류를 방지합니다.

타입 주석은 TypeScript에서 변수, 함수 매개변수, 반환 값 등에 개발자가 직접 타입을 명시적으로 지정하는 것을 말합니다. TypeScript는 타입 추론을 통해 자동으로 타입을 결정하지만, 타입 주석을 사용…

전체 모범답안 펼치기

타입 주석은 TypeScript에서 변수, 함수 매개변수, 반환 값 등에 개발자가 직접 타입을 명시적으로 지정하는 것을 말합니다. TypeScript는 타입 추론을 통해 자동으로 타입을 결정하지만, 타입 주석을 사용하면 코드의 의도를 더 명확하게 드러내고 예상치 못한 타입 관련 오류를 컴파일 시점에 미리 발견할 수 있습니다.

주로 타입 추론이 어렵거나, 명확한 타입 정의가 필요한 경우에 사용합니다. 예를 들어, 복잡한 객체 구조를 다루거나, any 타입의 사용을 피하고 싶을 때 타입 주석을 활용합니다. 또한, 코드 가독성을 높이고 다른 개발자와의 협업을 원활하게 하기 위해서도 사용합니다.

let message: string = "Hello, TypeScript!";
function greet(name: string): string {
  return `Hello, ${name}!`;
}
#타입 추론#명시적 타입#코드 가독성#컴파일 시점 오류#any 타입 회피

이 질문 단독 페이지 →

Q3 기초

TypeScript의 기본 타입(Basic Types) 중 'string', 'number', 'boolean' 외에 'any'와 'unknown' 타입은 각각 어떤 용도로 사용되며, 둘의 차이점은 무엇인가요?

힌트 · 'any'는 모든 타입을 허용하여 타입 검사를 비활성화하고, 'unknown'은 타입 검사를 유지하면서도 유연성을 제공합니다.

TypeScript에서 string, number, boolean 외에 any와 unknown 타입은 유연성을 확보하기 위해 사용됩니다.

전체 모범답안 펼치기

TypeScript에서 string, number, boolean 외에 anyunknown 타입은 유연성을 확보하기 위해 사용됩니다.

any는 모든 타입의 값을 허용하며, 사실상 타입 검사를 비활성화합니다. 컴파일 타임에 타입 에러를 발생시키지 않지만, 런타임 에러로 이어질 가능성이 있습니다.

unknown 역시 모든 타입의 값을 할당받을 수 있지만, any와 달리 타입 검사를 유지합니다. unknown 타입의 값을 사용하기 전에 타입 단언(Type Assertion)이나 타입 좁히기(Type Narrowing)를 통해 구체적인 타입을 명시해야 합니다.

둘의 가장 큰 차이점은 타입 안정성입니다. any는 타입 검사를 느슨하게 만들어 개발 편의성을 높이지만, 타입 안정성을 해칠 수 있습니다. 반면 unknown은 타입 검사를 통해 타입 안정성을 유지하면서도 유연성을 제공합니다. 따라서 가능한 한 unknown을 사용하는 것이 좋습니다.

#타입 검사#컴파일 타임#런타임#타입 단언#타입 안정성

이 질문 단독 페이지 →

Q4 기초

TypeScript의 'interface'는 무엇이며, 객체의 형태를 정의할 때 어떻게 활용할 수 있는지 간단한 예시와 함께 설명해주세요.

힌트 · 객체가 가져야 할 속성과 메서드의 형태를 정의하는 데 사용되며, 코드의 일관성과 재사용성을 높입니다.

TypeScript에서 'interface'는 객체의 '모양'을 정의하는 역할을 합니다. 어떤 객체가 특정 속성과 메서드를 가져야 하는지 미리 약속하는 일종의 '계약'이라고 생각하시면 됩니다.

전체 모범답안 펼치기

TypeScript에서 'interface'는 객체의 '모양'을 정의하는 역할을 합니다. 어떤 객체가 특정 속성과 메서드를 가져야 하는지 미리 약속하는 일종의 '계약'이라고 생각하시면 됩니다.

예를 들어, name 속성과 greet 메서드를 가진 Person 인터페이스를 정의할 수 있습니다.

interface Person {
  name: string;
  greet(message: string): void;
}

이렇게 정의하면, Person 인터페이스를 따르는 객체는 반드시 name 속성(문자열)과 greet 메서드(문자열 인자를 받고 반환값이 없는 함수)를 가져야 합니다. 이를 통해 코드의 안정성을 높이고, 개발자가 실수를 줄이도록 도와줍니다. 또한, 인터페이스는 코드의 재사용성을 높이는 데에도 기여합니다.

#타입 정의#구조 명세#계약(Contract)#Duck Typing#선언 합침(Declaration Merging)

이 질문 단독 페이지 →

Q5 기초

'type' 별칭(Type Alias)은 무엇이며, 'interface'와 비교했을 때 어떤 상황에서 'type' 별칭을 사용하는 것이 더 적합한가요?

힌트 · 'type' 별칭은 기본 타입, 유니온/인터섹션 타입, 튜플 등 다양한 타입 조합을 정의할 수 있어 더 유연합니다.

'type' 별칭은 TypeScript에서 기존 타입에 새로운 이름을 부여하는 기능입니다. 마치 변수처럼 타입을 참조할 수 있게 해주는 것이죠.

전체 모범답안 펼치기

'type' 별칭은 TypeScript에서 기존 타입에 새로운 이름을 부여하는 기능입니다. 마치 변수처럼 타입을 참조할 수 있게 해주는 것이죠.

'interface'와 비교했을 때, 'type' 별칭은 좀 더 광범위하게 사용될 수 있습니다. 특히 유니온 타입이나 튜플 타입을 정의할 때 유용합니다. 예를 들어, type Result = Success | Failure처럼 여러 타입 중 하나를 나타내거나, type Point = [number, number]처럼 튜플을 정의할 때 'type' 별칭이 더 적합합니다.

또한, 원시 타입에 별칭을 부여하거나, 타입 연산을 수행할 때도 'type' 별칭을 사용합니다. 반면 'interface'는 주로 객체 타입을 정의하고 선언 병합을 지원한다는 특징이 있습니다. 따라서 객체 구조를 정의하고 확장해야 할 때는 'interface'를, 그 외 다양한 타입 조합이나 연산이 필요할 때는 'type' 별칭을 선택하는 것이 좋습니다.

#유니온 타입#튜플#원시 타입#타입 연산#선언 병합

이 질문 단독 페이지 →

Q6 기초

TypeScript에서 함수에 타입을 정의하는 방법은 무엇이며, 매개변수와 반환 값에 타입을 명시하는 이유를 설명해주세요.

힌트 · 함수의 입력과 출력에 타입을 명시하여 잘못된 인자 전달이나 예상치 못한 반환 값으로 인한 오류를 방지합니다.

TypeScript에서 함수에 타입을 정의하는 방법은 크게 두 가지입니다. 첫째는 매개변수와 반환 값에 타입 애너테이션을 사용하는 것입니다. 예를 들어 function add(x: number, y: number):…

전체 모범답안 펼치기

TypeScript에서 함수에 타입을 정의하는 방법은 크게 두 가지입니다. 첫째는 매개변수와 반환 값에 타입 애너테이션을 사용하는 것입니다. 예를 들어 function add(x: number, y: number): number { return x + y; } 와 같이 콜론(:)을 사용하여 타입을 명시합니다. 둘째는 TypeScript의 타입 추론 기능을 활용하는 것입니다. 변수에 초기값을 할당하거나, 반환 값이 명확한 경우 타입을 생략할 수 있습니다.

매개변수와 반환 값에 타입을 명시하는 이유는 코드의 안정성을 높이기 위해서입니다. 타입을 지정함으로써 함수에 잘못된 타입의 인자가 전달되거나, 예상치 못한 타입의 반환 값이 나오는 것을 방지할 수 있습니다. 이는 개발 단계에서 오류를 미리 발견하고 수정하는 데 도움을 주며, 코드의 가독성과 유지보수성을 향상시키는 데 기여합니다. 또한, 정적 타입 검사를 통해 런타임 오류를 줄일 수 있습니다.

#타입 애너테이션#매개변수 타입#반환 타입#정적 타입#타입 추론

이 질문 단독 페이지 →

Q7 기초

'enum' 타입은 무엇이며, TypeScript에서 'enum'을 사용하는 주된 목적과 간단한 예시를 들어 설명해주세요.

힌트 · 관련된 상수 값들을 하나의 그룹으로 묶어 코드의 가독성과 유지보수성을 향상시키는 데 사용됩니다.

네, 'enum' 타입은 열거형이라고도 불리며, 관련된 상수들을 하나의 그룹으로 묶어 표현하는 타입입니다. TypeScript에서 'enum'을 사용하는 주된 목적은 코드의 가독성과 유지보수성을 높이는 데 있습니다.

전체 모범답안 펼치기

네, 'enum' 타입은 열거형이라고도 불리며, 관련된 상수들을 하나의 그룹으로 묶어 표현하는 타입입니다. TypeScript에서 'enum'을 사용하는 주된 목적은 코드의 가독성과 유지보수성을 높이는 데 있습니다.

예를 들어, 요일이라는 개념을 표현할 때, 'enum'을 사용하면 'Monday', 'Tuesday'와 같은 문자열 상수들을 하나의 'Day'라는 타입으로 묶을 수 있습니다. 이렇게 하면 오타를 방지하고, 코드 내에서 요일을 일관성 있게 사용할 수 있습니다.

enum Day {
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday,
}

let today: Day = Day.Monday;

이처럼 'enum'은 타입 안정성을 확보하고, 코드의 의미를 명확하게 만들어 개발 생산성을 향상시키는 데 도움을 줍니다.

#열거형#타입 안정성#가독성#유지보수성#상수 집합

이 질문 단독 페이지 →

읽기만으론 부족합니다 — 직접 말해보세요

패스잇 앱에서 TypeScript 질문에 직접 답하면 AI가 1:1로 답변을 코칭합니다.

TypeScript 면접 질문 — 중급

Q8 중급

TypeScript에서 여러 타입 중 특정 타입의 값을 안전하게 처리하기 위해 사용하는 타입 가드(Type Guards)의 종류와 각각의 사용 사례를 설명해 주세요.

힌트 · `typeof`, `instanceof`, `in` 연산자와 사용자 정의 타입 가드를 활용하여 런타임에 타입을 확인하고 범위를 좁히는 방법을 설명합니다.

타입스크립트에서 타입 가드는 여러 타입이 섞여 있을 때 특정 타입의 값을 안전하게 다루기 위해 사용합니다. 런타임에 타입을 확인하고 범위를 좁혀서 타입 에러를 방지하죠.

전체 모범답안 펼치기

타입스크립트에서 타입 가드는 여러 타입이 섞여 있을 때 특정 타입의 값을 안전하게 다루기 위해 사용합니다. 런타임에 타입을 확인하고 범위를 좁혀서 타입 에러를 방지하죠.

가장 기본적인 건 typeof 연산자입니다. 원시 타입(string, number, boolean 등)을 구분할 때 유용합니다. 예를 들어 typeof x === 'string'처럼 사용해서 문자열인 경우에만 특정 로직을 실행할 수 있습니다.

instanceof 연산자는 클래스의 인스턴스를 확인할 때 씁니다. x instanceof MyClass처럼 사용해서 특정 클래스의 인스턴스인 경우에만 해당 클래스의 메서드를 호출할 수 있습니다.

in 연산자는 객체에 특정 프로퍼티가 있는지 확인할 때 사용합니다. 'name' in x처럼 사용해서 객체 x에 'name' 프로퍼티가 있는 경우에만 접근할 수 있습니다.

마지막으로 사용자 정의 타입 가드를 만들 수도 있습니다. x is MyType 형태의 반환 타입을 가지는 함수를 만들어서 복잡한 타입 조건을 검사할 수 있습니다. 이를 통해 타입 체커에게 특정 조건 하에서 변수의 타입을 알려줄 수 있습니다.

#typeof#instanceof#in 연산자#사용자 정의 타입 가드#타입 좁히기

이 질문 단독 페이지 →

Q9 중급

공통된 속성을 가진 여러 인터페이스를 조합하여 판별된 유니언(Discriminated Unions)을 구성하는 방법과 이를 통해 얻을 수 있는 타입 안정성의 이점에 대해 설명해 주세요.

힌트 · 고유한 리터럴 타입 속성(discriminant)을 사용하여 유니언 멤버를 구분하고, `switch` 문 등으로 각 멤버의 타입을 안전하게 추론하는 방법을 설명합니다.

네, 판별된 유니언은 타입스크립트에서 여러 인터페이스를 묶어 하나의 타입으로 표현하면서, 각 인터페이스를 구분할 수 있는 속성을 추가하여 타입 안정성을 높이는 방법입니다.

전체 모범답안 펼치기

네, 판별된 유니언은 타입스크립트에서 여러 인터페이스를 묶어 하나의 타입으로 표현하면서, 각 인터페이스를 구분할 수 있는 속성을 추가하여 타입 안정성을 높이는 방법입니다.

각 인터페이스에 공통된 속성, 예를 들어 type이라는 속성을 추가하고, 각 인터페이스마다 type 속성에 고유한 리터럴 타입을 할당합니다. 이렇게 하면 유니언 타입을 사용할 때 type 속성 값을 확인하여 어떤 인터페이스가 사용되었는지 알 수 있습니다.

interface Circle {
  type: 'circle';
  radius: number;
}

interface Square {
  type: 'square';
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape) {
  switch (shape.type) {
    case 'circle':
      return Math.PI * shape.radius * shape.radius;
    case 'square':
      return shape.sideLength * shape.sideLength;
  }
}

switch 문이나 타입 가드를 사용하여 type 속성을 기반으로 타입을 좁히면, 타입스크립트 컴파일러는 각 분기에서 어떤 인터페이스가 사용되는지 정확하게 추론할 수 있습니다. 이를 통해 런타임 에러를 줄이고 코드의 안정성을 높일 수 있습니다.

#판별자#타입 좁히기#타입 가드#타입 안정성#합집합 타입

이 질문 단독 페이지 →

Q10 중급

TypeScript에서 제네릭(Generics)을 사용하는 주요 목적은 무엇이며, 제네릭 제약 조건(Generic Constraints)은 언제, 왜 필요한지 구체적인 코드 예시와 함께 설명해 주세요.

힌트 · 함수나 클래스에서 다양한 타입에 대해 유연하고 재사용 가능한 코드를 작성하기 위해 제네릭을 사용하며, 특정 속성이나 메서드를 가진 타입으로 제한할 때 제약 조건이 필요합니다.

TypeScript에서 제네릭을 사용하는 주된 목적은 타입 안정성을 유지하면서 코드 재사용성을 높이는 것입니다. 제네릭을 사용하면 함수나 클래스가 다양한 타입에 대해 동작할 수 있도록 일반화할 수 있습니다.

전체 모범답안 펼치기

TypeScript에서 제네릭을 사용하는 주된 목적은 타입 안정성을 유지하면서 코드 재사용성을 높이는 것입니다. 제네릭을 사용하면 함수나 클래스가 다양한 타입에 대해 동작할 수 있도록 일반화할 수 있습니다.

제네릭 제약 조건은 특정 타입만 허용하도록 제한해야 할 때 필요합니다. 예를 들어, 특정 속성을 가진 객체만 처리하는 함수를 만들고 싶을 때 제약 조건을 사용합니다.

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

위 예시에서 Lengthwise 인터페이스를 사용하여 arglength 속성을 가지고 있는지 확인합니다. 이렇게 하면 length 속성이 없는 타입이 전달되는 것을 방지하여 타입 안정성을 확보할 수 있습니다.

#타입 안정성#코드 재사용성#타입 추론#제네릭 제약 조건#유연성

이 질문 단독 페이지 →

Q11 중급

TypeScript의 내장 유틸리티 타입 중 `Partial<T>`, `Pick<T, K>`, `Omit<T, K>` 각각의 역할과 실제 프로젝트에서 어떤 상황에 유용하게 활용될 수 있는지 설명해 주세요.

힌트 · `Partial`은 모든 속성을 선택적으로 만들고, `Pick`은 특정 속성만 선택하며, `Omit`은 특정 속성을 제외하여 새로운 타입을 생성하는 데 사용됩니다.

TypeScript의 내장 유틸리티 타입 Partial<T, Pick<T, K, Omit<T, K는 기존 타입을 기반으로 새로운 타입을 만들 때 유용합니다.

전체 모범답안 펼치기

TypeScript의 내장 유틸리티 타입 Partial<T>, Pick<T, K>, Omit<T, K>는 기존 타입을 기반으로 새로운 타입을 만들 때 유용합니다.

Partial<T>은 타입 T의 모든 속성을 선택적(optional)으로 만들어 줍니다. 예를 들어, 사용자 정보 인터페이스가 있을 때, 사용자 정보 업데이트 시 모든 필드를 필수로 받지 않고 일부만 받도록 할 때 유용합니다.

Pick<T, K>는 타입 T에서 K에 해당하는 속성만 선택하여 새로운 타입을 생성합니다. 특정 데이터만 필요한 API 응답 타입을 정의할 때 유용하게 사용할 수 있습니다.

Omit<T, K>는 타입 T에서 K에 해당하는 속성을 제외하고 새로운 타입을 생성합니다. 예를 들어, 사용자 정보 인터페이스에서 비밀번호 관련 속성을 제외한 공개 프로필 정보를 정의할 때 사용할 수 있습니다.

#타입 변환#부분 타입#선택적 속성#속성 선택#속성 제거

이 질문 단독 페이지 →

Q12 중급

JavaScript 라이브러리를 TypeScript 프로젝트에서 사용해야 할 때 `.d.ts` 선언 파일이 어떤 역할을 하는지 설명하고, 직접 선언 파일을 작성해야 하는 경우와 기존 선언 파일을 활용하는 방법을 비교하여 설명해 주세요.

힌트 · `.d.ts` 파일은 기존 JavaScript 코드에 대한 타입 정보를 제공하여 TypeScript 컴파일러가 타입 검사를 수행할 수 있게 하며, `@types` 패키지나 직접 `declare` 키워드를 사용하여 작성할 수 있습니다.

.d.ts 파일은 JavaScript 라이브러리를 TypeScript 프로젝트에서 사용할 때 타입 정보를 제공하는 역할을 합니다. TypeScript 컴파일러는 이 파일을 통해 JavaScript 코드의 타입을 이해…

전체 모범답안 펼치기

.d.ts 파일은 JavaScript 라이브러리를 TypeScript 프로젝트에서 사용할 때 타입 정보를 제공하는 역할을 합니다. TypeScript 컴파일러는 이 파일을 통해 JavaScript 코드의 타입을 이해하고, 타입 검사를 수행하여 잠재적인 오류를 미리 발견할 수 있도록 돕습니다.

만약 라이브러리에 이미 @types 패키지가 존재한다면, 해당 패키지를 설치하여 간편하게 타입 정보를 활용할 수 있습니다. 하지만 타입 정의가 제공되지 않는 경우에는 직접 .d.ts 파일을 작성해야 합니다. declare 키워드를 사용하여 변수, 함수, 클래스 등의 타입을 정의할 수 있습니다.

기존 선언 파일을 활용하는 것이 가장 효율적이지만, 없는 경우에는 직접 작성하여 타입 안정성을 확보하고 컴파일 타임에 오류를 검출할 수 있도록 하는 것이 중요합니다. DefinitelyTyped 저장소에 기여하는 방법도 고려해볼 수 있습니다.

#타입 정의#타입 안정성#컴파일 타임 검사#ambient declaration#DefinitelyTyped

이 질문 단독 페이지 →

Q13 중급

TypeScript에서 타입 별칭(Type Aliases)과 인터페이스(Interfaces)는 모두 객체 타입을 정의하는 데 사용됩니다. 두 가지의 주요 차이점은 무엇이며, 각각 어떤 상황에서 더 적합한지 설명해 주세요.

힌트 · 인터페이스는 선언적 병합(Declaration Merging)이 가능하며 주로 객체 타입을 정의하는 데 사용되고, 타입 별칭은 유니언/인터섹션 타입, 원시 타입 등 더 다양한 타입에 대한 별칭을 정의할 수 있습니다.

TypeScript에서 타입 별칭과 인터페이스는 객체 타입을 정의하는 데 사용될 수 있지만, 몇 가지 중요한 차이점이 있습니다.

전체 모범답안 펼치기

TypeScript에서 타입 별칭과 인터페이스는 객체 타입을 정의하는 데 사용될 수 있지만, 몇 가지 중요한 차이점이 있습니다.

가장 큰 차이점은 인터페이스는 "선언 병합(Declaration Merging)"이 가능하다는 점입니다. 같은 이름의 인터페이스가 여러 번 선언되면 컴파일러가 이를 자동으로 병합합니다. 반면, 타입 별칭은 같은 이름으로 여러 번 선언할 수 없습니다.

또한, 타입 별칭은 객체 타입뿐만 아니라 유니온 타입, 인터섹션 타입, 원시 타입 등 더 넓은 범위의 타입에 대한 별칭을 정의할 수 있습니다. 예를 들어 type StringOrNumber = string | number; 와 같이 사용할 수 있습니다.

일반적으로 객체 타입을 정의하고 확장 가능성이 높다면 인터페이스를 사용하는 것이 좋습니다. 클래스에서 implements 키워드를 사용하여 인터페이스를 구현할 수도 있습니다. 반면, 유니온 타입이나 튜플 타입 등 복잡한 타입을 정의하거나, 단순히 기존 타입을 더 명확하게 표현하고 싶을 때는 타입 별칭이 더 적합합니다.

#선언 병합#유니온 타입#원시 타입#구현#extends/implements

이 질문 단독 페이지 →

Q14 중급

TypeScript의 데코레이터(Decorators)는 무엇이며, 클래스, 메서드, 속성 데코레이터의 기본적인 사용 목적과 실제 애플리케이션에서 어떤 방식으로 활용될 수 있는지 예시를 들어 설명해 주세요.

힌트 · 데코레이터는 클래스, 메서드, 속성 등에 메타데이터를 추가하거나 동작을 변경하는 함수로, AOP 패턴을 구현하거나 프레임워크에서 설정 정보를 주입하는 데 활용됩니다. (현재는 실험적 기능)

TypeScript의 데코레이터는 클래스, 메서드, 속성 등에 추가적인 메타데이터를 제공하거나 동작을 수정하는 함수입니다. 일종의 "장식"이라고 생각하면 이해하기 쉽습니다.

전체 모범답안 펼치기

TypeScript의 데코레이터는 클래스, 메서드, 속성 등에 추가적인 메타데이터를 제공하거나 동작을 수정하는 함수입니다. 일종의 "장식"이라고 생각하면 이해하기 쉽습니다.

클래스 데코레이터는 클래스 자체를 수정하거나 확장하는 데 사용됩니다. 예를 들어, 싱글톤 패턴을 구현하거나, 클래스에 로깅 기능을 추가할 수 있습니다.

메서드 데코레이터는 메서드의 동작을 가로채거나 수정합니다. AOP(Aspect-Oriented Programming)에서 로깅, 권한 검사 등에 활용될 수 있습니다.

속성 데코레이터는 속성의 접근 방식을 제어하거나, 유효성 검사를 수행하는 데 사용됩니다. 예를 들어, 데이터 바인딩 프레임워크에서 속성의 변경을 감지하는 데 활용될 수 있습니다.

데코레이터는 현재 TypeScript에서 실험적인 기능이지만, 코드의 재사용성을 높이고 유지보수를 용이하게 하는 강력한 도구입니다.

#메타데이터#함수 데코레이터#클래스 데코레이터#메서드 데코레이터#속성 데코레이터

이 질문 단독 페이지 →

TypeScript 면접 질문 — 심화

Q15 심화

복잡한 비동기 데이터 처리 로직에서, 특정 조건에 따라 반환 타입이 동적으로 결정되는 함수를 TypeScript로 어떻게 안전하게 모델링하고 구현할 수 있을까요? 특히, 제네릭과 조건부 타입을 활용하여 Union Type을 분해하고 재구성하는 고급 기법을 설명해주세요.

힌트 · `infer` 키워드와 분산 조건부 타입을 사용하여 유니온 타입을 개별적으로 처리하고, 이를 재구성하는 방식을 고려해야 합니다. `Exclude`나 `Extract`와 같은 유틸리티 타입의 원리를 이해하는 것이 중요합니다.

네, 좋은 질문입니다. TypeScript에서 복잡한 비동기 데이터 처리 로직을 다룰 때, 반환 타입이 동적으로 결정되는 함수를 안전하게 모델링하는 것은 중요합니다.

전체 모범답안 펼치기

네, 좋은 질문입니다. TypeScript에서 복잡한 비동기 데이터 처리 로직을 다룰 때, 반환 타입이 동적으로 결정되는 함수를 안전하게 모델링하는 것은 중요합니다.

제네릭과 조건부 타입을 활용하면 이 문제를 해결할 수 있습니다. 먼저, 제네릭을 사용하여 함수의 입력 타입에 따라 반환 타입을 결정합니다. 조건부 타입은 특정 조건에 따라 다른 타입을 반환하도록 정의할 수 있습니다.

Union Type을 분해하고 재구성할 때는 infer 키워드와 분산 조건부 타입을 활용합니다. infer는 조건부 타입 내에서 타입을 추론하는 데 사용되며, 분산 조건부 타입은 Union Type의 각 멤버에 대해 조건부 타입을 개별적으로 적용합니다. 예를 들어, ExcludeExtract와 같은 유틸리티 타입을 사용하여 특정 타입을 제외하거나 추출할 수 있습니다.

Promise를 반환하는 비동기 함수의 경우, 이 모든 기법을 조합하여 타입 안정성을 확보할 수 있습니다. 복잡한 로직일수록 타입 정의를 명확하게 하는 것이 중요합니다.

#제네릭#조건부 타입#Union Type#타입 추론#Promise

이 질문 단독 페이지 →

Q16 심화

서드파티 라이브러리(예: `express` 또는 `lodash`)의 타입 정의가 불완전하거나, 애플리케이션 특정 요구사항에 맞춰 기존 타입을 확장해야 할 때, TypeScript에서 안전하고 모듈화된 방식으로 이를 처리하는 방법을 설명해주세요. 특히, 전역 선언 확장과 모듈 확장 간의 차이점 및 사용 시나리오를 비교하여 설명해주세요.

힌트 · `declare global`과 `declare module` 구문을 사용하여 전역 또는 특정 모듈의 타입을 확장할 수 있습니다. 확장하려는 대상이 전역 스코프인지, 아니면 특정 모듈의 내보내진 인터페이스인지에 따라 적절한 방법을 선택해야 합니다.

네, 좋은 질문입니다. TypeScript에서 서드파티 라이브러리의 타입 정의를 확장하는 방법은 크게 전역 선언 확장과 모듈 확장 두 가지가 있습니다.

전체 모범답안 펼치기

네, 좋은 질문입니다. TypeScript에서 서드파티 라이브러리의 타입 정의를 확장하는 방법은 크게 전역 선언 확장과 모듈 확장 두 가지가 있습니다.

전역 선언 확장은 declare global 블록을 사용하여 전역 스코프에 존재하는 타입 정의를 확장하는 방식입니다. 예를 들어, window 객체에 새로운 속성을 추가하고 싶을 때 사용합니다. 하지만 전역 스코프를 오염시킬 수 있으므로 주의해야 합니다.

모듈 확장은 declare module 구문을 사용하여 특정 모듈의 타입 정의를 확장하는 방식입니다. 예를 들어, express 모듈의 Request 인터페이스에 사용자 정의 속성을 추가하고 싶을 때 사용합니다. 이 방법은 특정 모듈에만 영향을 미치므로 전역 스코프 오염을 방지할 수 있습니다.

어떤 방법을 선택할지는 확장하려는 대상이 전역 스코프에 있는지, 아니면 특정 모듈의 내보내진 인터페이스인지에 따라 결정됩니다. 일반적으로 모듈 확장이 더 안전하고 모듈화된 방식이라고 생각합니다. 타입 선언 파일(.d.ts)을 만들어서 확장 내용을 정의하고, tsconfig.json 파일에서 해당 파일을 포함시키는 방식으로 관리하면 더욱 깔끔하게 유지할 수 있습니다.

#선언 병합#모듈 확장#전역 선언 확장#타입 선언 파일 (.d.ts)#namespace

이 질문 단독 페이지 →

Q17 심화

대규모 모노레포 환경에서 TypeScript 프로젝트를 관리할 때, 빌드 성능을 최적화하고 타입 의존성을 효율적으로 관리하기 위한 `tsconfig.json` 설정 전략에 대해 설명해주세요. 특히 `project references`의 도입 배경, 동작 방식, 그리고 이를 활용하여 얻을 수 있는 이점을 구체적인 예시와 함께 설명해주세요.

힌트 · `composite`, `declarationMap`, `incremental` 등의 `tsconfig` 옵션과 `references` 배열을 사용하여 다중 프로젝트 간의 의존성을 명시하고 증분 빌드를 활성화할 수 있습니다. 이를 통해 빌드 시간 단축과 타입 검사의 효율성을 높일 수 있습니다.

모노레포 환경에서 TypeScript 프로젝트 빌드 성능 최적화는 중요한 과제입니다. tsconfig.json 설정을 통해 이를 효과적으로 관리할 수 있습니다.

전체 모범답안 펼치기

모노레포 환경에서 TypeScript 프로젝트 빌드 성능 최적화는 중요한 과제입니다. tsconfig.json 설정을 통해 이를 효과적으로 관리할 수 있습니다.

핵심은 project references를 활용하는 것입니다. 이는 프로젝트 간 의존성을 명시적으로 선언하는 기능입니다. composite 옵션을 활성화하고, references 배열에 의존하는 프로젝트의 경로를 지정합니다.

예를 들어, ui-librarycore 라이브러리에 의존한다면, ui-librarytsconfig.jsoncore를 참조하도록 설정합니다.

{
  "compilerOptions": {
    "composite": true
  },
  "references": [{ "path": "../core" }]
}

이렇게 하면 TypeScript 컴파일러는 의존성 그래프를 이해하고, 변경된 부분만 증분 빌드하여 전체 빌드 시간을 단축할 수 있습니다. 또한, 타입 정보(.d.ts)를 공유하여 타입 검사 속도도 향상됩니다. declarationMap 옵션을 함께 사용하면 디버깅 경험도 개선할 수 있습니다.

#모노레포#tsconfig.json#Project References#Incremental Build#타입 의존성

이 질문 단독 페이지 →

Q18 심화

런타임에 동적으로 생성되는 데이터 스키마(예: JSON Schema)에 대해, 이를 기반으로 TypeScript 타입 추론을 수행하고 컴파일 타임에 유효성 검사를 강화하는 '타입 레벨 프로그래밍' 기법을 어떻게 적용할 수 있을까요? 특히, 타입 가드와 커스텀 유틸리티 타입을 활용하여 복잡한 데이터 구조의 안정성을 확보하는 방안을 제시해주세요.

힌트 · 런타임 유효성 검사 라이브러리(예: Zod, Yup)와 TypeScript의 타입 추론을 연동하는 방식을 고려하거나, 조건부 타입과 제네릭을 사용하여 스키마 정의로부터 타입을 동적으로 생성하는 기법을 활용할 수 있습니다.

네, 좋은 질문입니다. 런타임에 동적으로 생성되는 JSON Schema로부터 TypeScript 타입을 추론하고 컴파일 타임 유효성 검사를 강화하는 방법은 매우 중요합니다.

전체 모범답안 펼치기

네, 좋은 질문입니다. 런타임에 동적으로 생성되는 JSON Schema로부터 TypeScript 타입을 추론하고 컴파일 타임 유효성 검사를 강화하는 방법은 매우 중요합니다.

저는 Zod나 Yup과 같은 런타임 유효성 검사 라이브러리와 TypeScript의 타입 추론을 연동하는 방식을 선호합니다. 먼저, 런타임에 JSON Schema를 기반으로 Zod 스키마를 생성합니다. 그 다음, z.infer<>를 사용하여 Zod 스키마로부터 TypeScript 타입을 추론합니다.

타입 가드를 활용하여 런타임에 데이터를 검증하고, 검증된 데이터에 대해서만 추론된 타입을 적용할 수 있습니다. 또한, 조건부 타입과 제네릭을 사용하여 스키마 정의로부터 복잡한 데이터 구조에 맞는 커스텀 유틸리티 타입을 생성하여 타입 안정성을 더욱 강화할 수 있습니다.

예를 들어, type MyType = Infer<typeof myZodSchema> 와 같이 Zod 스키마로부터 타입을 추출할 수 있습니다. 이를 통해 런타임 유효성 검사와 컴파일 타임 타입 검사를 동시에 만족시킬 수 있습니다.

#JSON Schema#타입 추론#타입 가드#유틸리티 타입#컴파일 타임 유효성 검사

이 질문 단독 페이지 →

Q19 심화

TypeScript의 Decorator를 활용하여 메타데이터 기반의 AOP(Aspect-Oriented Programming) 패턴을 구현할 때, 타입 안전성을 어떻게 확보할 수 있을까요? 특히 `reflect-metadata` 라이브러리와 함께 사용될 때, 컴파일 타임에 타입 정보를 활용하여 런타임에 메타데이터를 안전하게 주입하고 사용하는 방법에 대해 설명해주세요.

힌트 · `emitDecoratorMetadata` 컴파일러 옵션과 `reflect-metadata`를 통해 클래스, 메서드, 속성 등에 대한 타입 정보를 런타임에 조회할 수 있습니다. 이를 활용하여 데코레이터가 적용될 대상의 타입을 검사하고 적절한 로직을 수행하도록 설계할 수 있습니다.

TypeScript 데코레이터를 활용한 AOP 구현 시 타입 안전성을 확보하는 방법은 크게 두 가지 측면에서 고려할 수 있습니다.

전체 모범답안 펼치기

TypeScript 데코레이터를 활용한 AOP 구현 시 타입 안전성을 확보하는 방법은 크게 두 가지 측면에서 고려할 수 있습니다.

첫째, emitDecoratorMetadata 컴파일러 옵션과 reflect-metadata 라이브러리를 활용하여 런타임에 타입 정보를 얻습니다. 데코레이터 팩토리를 사용하여 데코레이터가 적용될 대상의 타입을 추론하고, 이를 기반으로 타입 가드를 적용하여 런타임에 타입 검사를 수행합니다. 예를 들어, 특정 타입의 인자만 허용하는 데코레이터를 만들 수 있습니다.

둘째, 제네릭 타입과 조건부 타입을 활용하여 데코레이터의 타입 안정성을 강화합니다. 데코레이터 팩토리에 제네릭 타입을 적용하여 데코레이터가 적용될 대상의 타입에 따라 다른 로직을 수행하도록 설계할 수 있습니다. 조건부 타입을 사용하여 특정 조건에 따라 데코레이터의 반환 타입을 변경할 수도 있습니다.

이러한 방법들을 통해 컴파일 타임에 타입 정보를 활용하여 런타임에 메타데이터를 안전하게 주입하고 사용할 수 있으며, TypeScript의 강력한 타입 시스템을 최대한 활용하여 AOP 구현의 타입 안전성을 확보할 수 있습니다.

#데코레이터 팩토리#타입 추론#타입 가드#제네릭 타입#조건부 타입

이 질문 단독 페이지 →

Q20 심화

중첩된 객체 구조에서 깊은(deep) 불변성(immutability)을 강제하는 TypeScript 타입을 어떻게 설계할 수 있을까요? 특히, 재귀적 타입 정의와 Mapped Types를 조합하여 모든 속성이 `readonly`인 중첩 객체 타입을 생성하는 고급 기법을 설명해주세요.

힌트 · 인덱스 시그니처와 조건부 타입을 사용하여 객체의 속성이 객체인 경우 재귀적으로 `DeepReadonly` 타입을 적용하고, 그렇지 않은 경우 `readonly`를 적용하는 방식으로 구현할 수 있습니다.

네, "중첩된 객체 구조에서 깊은 불변성을 강제하는 TypeScript 타입 설계"에 대한 답변 드리겠습니다.

전체 모범답안 펼치기

네, "중첩된 객체 구조에서 깊은 불변성을 강제하는 TypeScript 타입 설계"에 대한 답변 드리겠습니다.

TypeScript에서 깊은 불변성을 구현하려면 재귀적 타입과 Mapped Types를 활용해야 합니다. 먼저, Mapped Types를 사용하여 객체의 모든 속성을 readonly로 만들 수 있습니다. 핵심은 조건부 타입을 사용하여 속성이 객체인지 확인하고, 객체라면 재귀적으로 DeepReadonly 타입을 적용하는 것입니다.

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

이 타입은 객체의 각 키에 대해, 해당 키의 타입이 객체이면 DeepReadonly를 재귀적으로 적용하고, 그렇지 않으면 readonly를 적용합니다. 이렇게 하면 중첩된 모든 객체의 속성이 불변하게 됩니다. 인덱스 시그니처를 통해 객체의 모든 속성에 접근하고, 조건부 타입을 통해 타입 추론을 수행하여 깊은 불변성을 효과적으로 구현할 수 있습니다.

#재귀적 타입#Mapped Types#Deep Readonly#타입 추론#조건부 타입

이 질문 단독 페이지 →

Q21 심화

TypeScript 4.0에서 도입된 Variadic Tuple Types를 활용하여, 인자의 개수나 타입이 동적으로 변하는 함수 시그니처를 어떻게 타입 안전하게 정의하고 활용할 수 있을까요? 특히, 함수 오버로드와 조합하여 유연하면서도 강력한 타입 추론을 제공하는 방법을 설명해주세요.

힌트 · `...rest` 매개변수에 `[...T]`와 같은 형태로 Variadic Tuple Types를 적용하여 인자의 길이나 타입을 가변적으로 정의할 수 있습니다. 이를 통해 함수 오버로드의 복잡성을 줄이고 더 유연한 함수 시그니처를 만들 수 있습니다.

TypeScript 4.0의 Variadic Tuple Types는 인자 개수나 타입이 동적으로 변하는 함수를 타입 안전하게 정의하는 데 매우 유용합니다. ...rest 매개변수와 함께 [...T] 형태를 사용하면,…

전체 모범답안 펼치기

TypeScript 4.0의 Variadic Tuple Types는 인자 개수나 타입이 동적으로 변하는 함수를 타입 안전하게 정의하는 데 매우 유용합니다. ...rest 매개변수와 함께 [...T] 형태를 사용하면, 튜플 타입 T에 따라 인자의 타입과 개수가 달라지는 함수를 만들 수 있습니다.

예를 들어, 여러 타입의 인자를 받아 처리하는 함수를 생각해 봅시다. 함수 오버로드를 사용하면 각 경우마다 시그니처를 정의해야 하지만, Variadic Tuple Types를 활용하면 제네릭과 함께 더 간결하게 표현할 수 있습니다.

function processData<T extends any[]>(...args: [...T]): void {
  // args를 기반으로 데이터 처리
}

이때, 함수 오버로드와 조합하면 더욱 강력한 타입 추론을 제공할 수 있습니다. 특정 타입의 인자가 들어왔을 때, 다른 타입으로 변환하거나 특정 로직을 수행하도록 정의할 수 있습니다. Variadic Tuple Types는 함수 오버로드의 복잡성을 줄이면서도 유연하고 타입 안전한 함수 시그니처를 가능하게 합니다.

#Variadic Tuple Types#제네릭#함수 오버로드#타입 추론#타입 안전성

이 질문 단독 페이지 →

함께 보면 좋은 프론트엔드 개발 면접 질문

← 전체 면접 질문 카테고리 보기

보유한 TypeScript 질문은 이게 전부가 아닙니다

패스잇 앱에는 직무별 면접 질문 수천 개와 모범답안이 담겨 있습니다. AI 모의면접으로 직접 답하고, 약점을 분석받아 보세요.