프로그래밍프론트엔드/풀스택 개발자

TypeScript에서 클래스 생성자의 타입은 어떻게 작동하며 상속 시 어떤 어려움이 발생할 수 있나요?

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

답변.

질문의 배경

원래 JavaScript는 클래스와 그 생성자에 대한 엄격한 타입을 지원하지 않아 런타임 오류를 초래했었습니다. TypeScript는 더 안전한 프로그래밍을 위해 타입 시스템을 추가하고 상속을 지원하는 생성자의 타입화를 도입했습니다. 이는 대규모 애플리케이션 개발에 중요합니다.

문제

TypeScript에서 생성자의 타입화는 생성자 시그니처, 생성되는 인스턴스의 타입 및 상속의 특징을 동시에 고려해야 합니다. 기본 클래스와 파생 클래스의 생성자 시그니처가 일치하지 않거나, 생성자의 입력 매개변수가 아닌 반환값만 타입화된 경우 문제가 발생합니다.

해결책

TypeScript에서는 특별한 시그니처를 통해 생성자를 명시적으로 타입화할 수 있으며, new (...args: any[]) => T 표현식을 사용합니다. 상속할 때는 시그니처의 일관성을 유지하고 기본 클래스를 올바르게 확장하는 것이 중요합니다.

코드 예:

class Animal { constructor(public name: string) {} } class Dog extends Animal { constructor(name: string, public breed: string) { super(name); } } // 생성자 타입 function createInstance<T>(C: new (...args: any[]) => T, ...args: any[]): T { return new C(...args); } const dog = createInstance(Dog, 'Rex', 'Labrador');

주요 특징:

  • 생성자 시그니처는 new로 선언되는 별개의 엔티티입니다.
  • 기본 클래스와 파생 클래스의 매개변수 호환성 유지
  • 타입화된 생성자를 통해 인스턴스를 일반적으로 생성할 수 있는 가능성

헷갈리는 질문들.

Java나 C#처럼 클래스에 여러 개의 생성자를 선언할 수 있나요?

아니요, TypeScript는 여러 생성자를 지원하지 않습니다. 오버로드 시그니처로 오버로딩을 구현해야 하며, 한 개의 구현을 사용하는 올바른 접근 방식은 다음과 같습니다:

class Example { constructor(x: string); constructor(x: number); constructor(x: number | string) { // 하나의 구현 } }

매개변수를 무시하고 생성자의 반환 타입만 타입화할 수 있나요?

아니요, 생성자 시그니처는 반드시 매개변수를 포함해야 합니다. 올바른 타입화 예:

interface Constructable<T> { new (...args: any[]): T; }

서브클래스에서 super 호출 없이 생성자를 선언하면 어떻게 되나요?

컴파일 오류가 발생합니다: 서브클래스의 생성자는 this에 접근하기 전에 super를 호출해야 합니다.

일반적인 오류 및 안티 패턴

  • 기본 클래스와 파생 클래스의 생성자 매개변수가 일치하지 않음
  • 자식 생성자에서 super 호출 누락
  • 팩토리를 통한 추상화 시 생성자의 잘못된 타입화

실제 사례

부정적 사례

프로젝트에서 기본 클래스 Animal을 생성자(name)와 함께 사용했으나, 상속받은 Dog에서 (name, breed)를 추가하고 시그니처를 올바르게 확장하는 것을 잊었습니다.

장점:

  • 새로운 매개변수를 문서화합니다.

단점:

  • 일반 팩토리를 통한 인스턴스 생성 시 호환성이 위반되고, 컴파일 시 오류가 발생합니다.

긍정적 사례

생성자 타입이 별도로 분리되어 있고, 팩토리 createInstance가 CorrectConstructable<T>를 통해 매개변수화되었으며, 시그니처가 준수되었습니다.

장점:

  • 타입의 안전성 및 예측 가능한 동작
  • 일반 함수를 쉽게 작성할 수 있습니다.

단점:

  • 타입화에 대한 보다 세심한 작업이 필요합니다.