Web/TypeScript

[TS] 타입스크립트 이해하기 - 타입 계층도, 타입 호환성

ansui 2024. 11. 11. 01:00

타입은 집합이다

❗타입은 동일한 속성과 특징을 갖는 집합이다.

 

1️⃣수퍼타입(부모타입) ⊃서브타입(자식타입)

타입은 값들을 포함하는 집합이고 서로 부모와 자식 관계를 지니며 계층도로 만들어 표현 가능하다.

예) number Type ⊃ number  literal Type

 

🔄타입 호환성

어떤 타입을 다른 타입으로 취급해도 괜찮은 지 판단하는 것

 

⭕업캐스팅: 서브타입(작은 타입)을 슈퍼타입(더 큰 타입)에 넣는 것 → 가능

❌다운 캐스팅: 슈퍼타입(더 큰 타입)을 서브타입(작은 타입)에 넣는 것 → 불가능

let num1: number = 10; // number 타입
let num2: 10 = 10; // literal 타입

num1 = num2; // 업캐스팅(가능)
num2 = num1; // 다운캐스팅(불가능)

타입 계층도와 함께 기본 타입 살펴보기

타입계층도

1️⃣ unknown 타입

// unknown 타입
function unknownExam() {
  // 업캐스팅이므로 가능
  let a: unknown = 1;
  let b: unknown = "hello";
  let c: unknown = true;
  let d: unknown = null;
  let e: unknown = undefined;

  let unknownVar: unknown;

  // 다운캐스팅이므로 오류 발생
  let num: number = unknownVar;
  let str: string = unknownVar;
  let bool: boolean = unknownVar;
}

 

2️⃣ never 타입

가장 아래에 있다 → 모든 타입의 서브타입이다 (= 공집합)

// never 타입
function neverExam() {
  function neverFunc(): never {
    while (true) {}
  }
  
  // 업캐스팅이므로 가능. 모든 타입에 할당 가능
  let num: number = neverFunc();
  let str: string = neverFunc();
  let bool: boolean = neverFunc();

  // 다운캐스팅이므로 오류 발생
  let never1: never = 10;
  let never2: never = "string";
  let never3: never = true;
}

 

3️⃣ void 타입

undefined의 수퍼 타입

// void 타입
function voidExam() {
  function voidFunc(): void {
    console.log("hi");
  }

  // void타입은 undefined의 수퍼타입
  // 업캐스팅이므로 가능
  let voidVar: void = undefined;
}

 

4️⃣ any 타입 - 치트키 타입

타입 계층도를 완벽히 무시한다.

// any 타입
function anyExam() {
  let unknownVar: unknown;
  let anyVar: any;
  let undefinedVar: undefined;
  let neverVar: never;

  // 다운캐스팅이지만 가능
  anyVar = unknownVar;
  undefinedVar = anyVar;

  // 예외: never타입은 순수한 공집합이므로 다운캐스팅 불가능
  neverVar = anyVar;
}

객체 타입의 호환성

1️⃣ 기본 타입 간의 호환성

특정 타입을 다른 타입으로 취급해도 괜찮은 지 판단

// 기본 타입간의 호환성
let num1: number = 10;
let num2: 10 = 10;

num1 = num2;

 

2️⃣ 객체 타입 간의 호환성

어떤 객체 타입을 다른 객체 타입으로 취급해도 괜찮은 지 판단

더 많은 프로퍼티를 정의하고 있는 타입이 서브타입 / 더 적은 프로퍼티를 정의하고 잇는 타입이 수퍼타입

// 객체 타입간의 호환성 예시 1
// 수퍼타입
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)
animal = dog;

// 다운캐스팅이므로 오류 발생
dog = animal;

 

// 객체 타입간의 호환성 예시 2
// 수퍼타입
type Book = {
  name: string;
  price: number;
};

// 서브타입
type ProgrammingBook = {
  name: string;
  price: number;
  skill: string;
};

let book: Book;
let programmingBook: ProgrammingBook = {
  name: "한 입 크기로 잘라먹는 타입스크립트",
  price: 33000,
  skill: "typescript",
};

// Book이 슈퍼타입, ProgrammingBook이 서브타입
book = programmingBook;

// 오류 발생
programmingBook = book;

 

❗초과 프로퍼티 검사

변수를 초기화할 때 객체 리터럴을 사용하면 실제 타입에는 정의하지 않은 프로퍼티를 작성하면 안되도록 막는 검사

// 초과 프로퍼티 검사
type Book = {
  name: string;
  price: number;
};

// 초과 프로퍼티 검사를 피하는 법
let book3: Book = programmingBook;
function func(book: Book) {
  func({
    name: "한 입 크기로 잘라먹는 타입스크립트",
    price: 33000,
    skill: "typescript", // 오류 발생
  });
  
  func(programmingBook);
}

 


이정환님의 인프런 강의 "한 입 크기로 잘라 먹는 타입스크립트(TypeScript)"를 참고하여 작성하였습니다.