[Typescript] 객체 타입의 호환성

Narcoker·2025년 5월 12일

Typescript

목록 보기
7/15

기본 타입의 호환성

이전 글 - [Typescript] 타입은 집합이다 - 타입 호환성 에 대한 간단 복습

  • 타입은 집합과 유사
  • 서브 타입은 슈퍼 타입에 할당할 수 있다. - 업 캐스팅
  • 슈퍼 타입은 서브 타입에 할당할 수 없다. - 다운 캐스팅
  • any는 업 캐스팅과 다운 캐스팅을 모두 허용한다.

기본 타입에서는

캐스팅 = 할당 값의 타입(집합)은 변수 값의 타입(집합)의 부분집합인가 아닌가

이라고 생각할 수 있다.

그러나 객체 타입에 이를 유사하게 적용하면 안된다.

상속에 빗대서 생각하는게 맞을 것 같다.
(extend 된 인터페이스(슈퍼 타입)의 모든 프로퍼티 포함..?)

객체 타입의 호환성

type Animal = {
  name: string;
  color: string;
};

type Dog = {
  name: string;
  color: string;
  breed: string;
};

let animal: Animal = {
  name: "기린",
  color: "yellow",
};

let dog: Dog = {
  name: "돌돌이",
  color: "brown",
  breed: "진도",
};

animal = dog; // ✅ OK
dog = animal; // ❌ NO

Dog 타입의 속성은 name color breed 를 가지고 있고
Animal 타입의 속성은 name color 를 가지고 있다.

기본 타입의 개념으로 생각해보면
Dog의 속성은 Animal 타입의 모든 속성을 가지고 있으니(부분집합이니)
Dog가 슈퍼 타입이고 Animal이 서브 타입 이지 않을까 할 수도 있다.

인간의 언어로 Animal이 Dog를 포함하는 것은 당연,
하지만 타입 이름이 A, D 였다면, 이전 이해도만으로는 판단하기 어려웠을 것 같다

하지만 정답은 코드에 주석으로 남긴 것처럼
Animal이 슈퍼 타입이고 Dog가 서브 타입이다.

구조적 타입 시스템

타입스크립트는 프로퍼티를 기준으로 타입을 정의하는 구조적 타입 시스템을 따른다.

Animal 타입(슈퍼 타입)은 name과 color 프로퍼티를 갖는 모든 객체들을 포함하는 집합
Dog 타입(서브 타입)은 두 속성에 추가로 breed 프로퍼티를 갖는 모든 객체를 포함하는 집합

정리하면 서브 타입 객체는 슈퍼타입 객체의 모든 프로퍼티를 가져야한다.

초과 프로퍼티 검사

type Book = {
  name: string;
  price: number;
};

type ProgrammingBook = {
  name: string;
  price: number;
  skill: string;
};

위와 같은 예제가 있을 때 다음은 에러를 발생한다.

let book: Book = { // 오류 발생
  name: "한 입 크기로 잘라먹는 리액트",
  price: 33000,
  skill: "reactjs",
};

book은 Book 타입이며 skill 프로퍼티를 가지고 있지 않는다.
그리고 할당된 리터럴 객체에는 skill 프로퍼티를 가지고 있기 때문에
발생하는 당연한 에러이다.

이러한 에러를 발생시키는 이유는 타입스크립트의 초과 프로퍼티 검사 기능 때문이다.
ProgrammingBook과 타입이 일치하지만 리터럴 객체 는 업 캐스팅을 지원하지 않는다.

이를 해결하기 위해서는 다음과 같이 리터럴 객체에 Type을 사전에 지정해줘야한다.

let programingBook: ProgrammingBook = { 
  name: "한 입 크기로 잘라먹는 리액트",
  price: 33000,
  skill: "reactjs",
};

let book: Book = programingBook;

초과 프로퍼티 검사는 함수의 매개변수에도 동일하게 동작한다.

function func(book: Book) {}

func({ // 오류 발생
  name: "한 입 크기로 잘라먹는 리액트",
  price: 33000,
  skill: "reactjs",
});

func(programmingBook); // 업 캐스팅 발동

번외 - 리터럴 객체에 타입 단언(as)으로도 해결 가능

let book: Book = { 
  name: "한 입 크기로 잘라먹는 리액트",
  price: 33000,
  skill: "reactjs",
} as ProgrammingBook;
function func(book: Book) {}

func({ // 오류 발생
  name: "한 입 크기로 잘라먹는 리액트",
  price: 33000,
  skill: "reactjs",
} as ProgrammingBook);

출처

인프런 - 한 입 크기로 잘라먹는 타입스크립트

profile
열정, 끈기, 집념의 Frontend Developer

0개의 댓글