타입스크립트 계층도 이해하기

Raccoon·2025년 4월 29일
post-thumbnail

본 포스팅은 한 입 크기로 잘라먹는 타입스크립트 강의를 참고하여 작성했습니다.사용된 모든 이미지는 해당 강의에서 가져온 것입니다. 문제가 될 소지가 있다면 댓글로 알려주세요. 바로 수정하겠습니다.

타입들은 부모와 자식 간의 관계를 가지며, 모든 타입들의 관계를 늘어놓으면 결국 타입 계층도가 완성된다.
타입 스크립트의 타입 계층도는 아래와 같다.

타입 계층도를 이해하게 되면, 타입 호환성 에 대해 이해할 수 있는데, 타입 호환성 이란 어떤 타입을 다른 타입으로 취급해도 괜찮은지 판단하는 것을 말한다.

위 사진으로 이해해보자면 number 타입을 number literal 타입으로 취급하는 것은 안되지만, 반대는 가능하다.
모든 정사각형은 직사각형으로 취급해도 괜찮지만, 반대는 안되는 관계가 이와같다.

이는 number 타입이 number literal 타입의 슈퍼타입(부모타입) 이기 때문에 가능하다.

let num1 : number = 10;
let num2 : 10 = 10;

num1 = num2; // OK

------------------------

let num1 : number = 10;
let num2 : 10 = 10;

num2 = num1; // error!!

이렇게 서브 타입의 값을 슈퍼 타입으로 취급하는 업 캐스팅 은 모든 상황에 가능하다.
반면에, 슈퍼 타입의 값을 서브 타입으로 취급하는 다운 캐스팅은 대부분의 상황에 불가능하다.

특수한 타입과 함께 타입 계층도를 코드 예시와 함께 이해해보자.

코드와 함께 살펴보기

unknown

계층도를 보면, unknown 타입은 가장 최상단에 위치한다.
즉, 모든 타입의 슈퍼타입 이다.

따라서, 모든 타입의 변수들을 unknown 타입으로 취급할 수 있다.(업 캐스팅)
하지만, 다운캐스팅은 불가능하다.

  let a: unknown = 1;
  let b: unknown = "hello";
  let c: unknown = true;
  let d: unknown = null;
  let e: unknown = undefined; // OK. upcasting 


  let unknownVar : unknown;
  let num: number = unknownVar // error!! downcasting

never

never 타입은 타입 계층도 최하단에 위치한다.
즉, 모든 타입의 서브타입 이고, 모든 집합의 부분집합이다. 이는 곧 공집합을 의미한다.

  function neverFunc(): never {
    while (true) {}
  }

  let num: number = neverFunc();
  let str: string = neverFunc();
  let bool: boolean = neverFunc(); // OK. upcasting

  let never1: never = 10; // error!! downcasting

코드를 보다보면 혼동이 올 수 있지만, 결국 업 캐스팅 은 모든 상황에 가능하고, 다운 캐스팅은 대부분의 상황에 불가능하다 라는 기준만 잡는다면, 해당 상황을 이해할 수 있다.

void

void 타입은 undefined의 슈퍼타입이고, 따라서 업캐스팅이 가능하다.

function voidFunc(): void {
  console.log("hi");
  return undefined;
}

let voidVar: void = undefined;

당연하게도 void 타입의 변수에 undefined를 할당할 수 있고, 이와 같은 맥락으로 void 타입의 함수가 undefined 를 반환 하도록 할 수 있다.

any

타입 계층도를 자세히 살펴보면, any 타입 머리 위에 치트키 라고 써있는 걸 볼 수 있다.
강의를 진행해주신 이정환 님이 이해하기 쉽도록 적어두신 용어이다.
이는 any 타입이 타입 계층도를 완벽하게 무시한다는 의미이다.

any 타입은 모든 타입의 슈퍼 타입 이면서, never 을 제외한 모든 타입의 서브 타입 이다.

타입 계층도로만 보면, unknown 타입의 변수를 any 타입의 변수에 넣는 것이 불가능해보이지만(다운 캐스팅), any 타입은 타입 계층도를 무시하기 때문에, 아래와 같이 다운 캐스팅이 가능하다.

let anyVar : any ;
let unknownVar : unknown;

anyVar = unknownVar;

타입 계층도를 볼 때 혼란이 올 수 있겠지만, any 타입에 한해서는 never 을 제외한 모든 관계가 무시된다고 생각하면 된다.
그래서 더더욱 위험한 타입이니, 사용을 지양하는게 좋겠다.

객체 타입의 호환성

다운 캐스팅과 업 캐스팅 개념을 가지고, 객체 타입 간의 호환성은 어떻게 되는지 알아보자.
객체 타입들도, 기본 타입처럼 슈퍼 타입서브 타입 관계를 가진다.

아래 코드를 보자.

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 타입을 보면, Dog 타입의 속성이 더 많기 때문에, 슈퍼 타입(부모 타입) 이라고 헷갈릴 수도 있다.
하지만, 객체 타입 관계에서는 속성이 더 적은 쪽이 슈퍼 타입 이다.

이는 정사각형직사각형 의 조건을 놓고 보면 이해하기 쉽다.
정사각형의 조건 : 직사각형의 조건 + 네 변의 길이가 모두 같다

정사각형직사각형 보다 더 많은 조건을 만족해야 하므로, 더 구체적인 형태이다.
따라서 정사각형직사각형의 자식이다.

이해할 때는 이런 비유로 이해하면 좋고, 속성이 더 적은쪽(조건이 더 까다로움)이 슈퍼 타입 이라는걸 기억해두자.

큰 나무 가지(슈퍼 타입)에서, 프로퍼티가 추가되면서 곁가지들(서브 타입)이 뻗어나오는 모습을 상상하자.

profile
꾸준함을 목표로 합니다.

0개의 댓글