개발새발

타입도 상속이 가능하다 본문

Typescript

타입도 상속이 가능하다

비숑주인 2025. 3. 22. 17:35

JavaScript에서는 class 문법을 통해 객체 간 상속이 가능하다. 마찬가지로 TypeScript에서도 타입끼리 상속(확장) 하여 중복 없이 타입을 재사용할 수 있다.

자바스크립트에서의 상속: 클래스 예시

class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark() {
    console.log(`${this.name} 멍멍`);
  }
}

class Cat extends Animal {
  meow() {
    console.log(`${this.name} 야옹`);
  }
}

 

 

Dog와 Cat 클래스는 Animal 클래스를 상속받기 때문에 name 속성을 중복해서 작성하지 않아도 된다. 

 

TypeScript에서의 상속: interface + extends

interface Animal {
  name: string;
}

interface Dog extends Animal {
  bark(): void;
}

interface Cat extends Animal {
  meow(): void;
}

 

 

  • Dog와 Cat은 Animal 타입을 상속받아 name 속성을 자동으로 포함한다.
  • 중복된 속성을 반복해서 쓰지 않아도 되어 코드의 유지보수가 쉽다. 

 

타입 별칭(type)도 상속처럼 확장 가능

type Animal = {
  name: string;
};

type Dog = Animal & {
  bark(): void;
};

type Cat = Animal & {
  meow(): void;
};

type Name = Cat['name']; // string

 

 

  • & 연산자를 사용해 타입을 교집합(intersection) 으로 결합하면 확장과 유사한 효과를 얻을 수 있다.
  • Cat 타입은 Animal의 name 속성을 상속하게 된다. 

 

| (유니언) 연산자와의 차이점

type Dog = Animal | { bark(): void }; // ❌

 

 

 

  • | 연산자는 합집합(union) 을 의미한다. 
  • Dog 타입은 Animal 타입이거나 { bark(): void } 타입일 수 있기 때문에, name 속성이 없을 수도 있는 타입이 되어 Cat['name']처럼 속성 접근 시 에러가 발생한다. 
  • 상속처럼 사용하고 싶으면 & 을 사용하자. 

 

interface와 type 간에도 상호 확장 가능

type Animal = { name: string };

interface Dog extends Animal {
  bark(): void;
}

interface Cat extends Animal {
  meow(): void;
}

type Name = Cat['name']; // string

 

 

 

  • type이 정의한 타입을 interface가 extends할 수 있다.
  • 반대로 interface 타입을 type에서 & 연산자로 확장하는 것도 가능하다. 

 

다중 상속도 가능하다

interface Dog extends Animal {
  bark(): void;
}

interface Cat extends Animal {
  meow(): void;
}

interface DogCat extends Dog, Cat {}

type MeowFn = DogCat['meow']; // () => void
type BarkFn = DogCat['bark']; // () => void

 

  • DogCat은 Dog와 Cat을 동시에 상속하여, bark와 meow를 모두 사용할 수 있는 타입이 된다. 
  • TypeScript는 다중 상속을 지원하며, 모든 부모 타입의 속성과 메서드를 합쳐 하나의 타입으로 생성한다. 

 

속성 타입 변경도 가능하다 (단, 호환성 유지 필수)

interface Merge {
  one: string;
  two: string;
}

interface Merge2 extends Merge {
  one: 'h' | 'w';      // ✅ string의 하위 타입이므로 가능
  two: '123';          // ✅ string의 하위 타입이므로 가능
}

 

 

 

하지만 아래처럼 전혀 다른 타입으로 변경하려 하면 오류가 발생한다. 

 

interface Merge2 extends Merge {
  two: 123; // ❌ number는 string에 대입 불가
}

 

자식 타입에서 부모 속성을 override 할 수는 있지만, 대입 가능성(subtyping) 을 만족해야 한다.

 

실무에서의 활용 포인트

공통 속성 묶기

interface BaseUser {
  id: string;
  createdAt: Date;
}

interface AdminUser extends BaseUser {
  role: 'admin';
}

interface NormalUser extends BaseUser {
  role: 'user';
}

 

교차 타입으로 기능 확장

 

type WithMeta = {
  metadata: Record<string, any>;
};

type EnrichedUser = BaseUser & WithMeta;

 

 

개념 문법
타입 상속 (interface) interface A extends B interface 간 상속
타입 확장 (type) type A = B & C type 간 확장
interface ← type 확장 interface A extends TypeAlias 가능
type ← interface 확장 type A = Interface & {} 가능
다중 상속 interface A extends B, C 여러 타입 동시에 확장
속성 override 조건 서브타입 관계 만족 시 가능 상속한 타입보다 좁아야 함