본문 바로가기
Web

[Typescript] 타입 단언, 타입 가드

by r4bb1t 2023. 11. 21.
반응형

타입스크립트 컴파일러는 코드에서 타입을 추론하는데, 컴파일러가 추론한 타입을 무시하고 우리가 원하는 타입으로 강제할 수 있습니다. 이를 타입 단언(Type Assertion)이라고 합니다.

type AnimalType = "cat" | "dog";

let cat = "cat";

이런 코드가 있을 때, 타입스크립트 컴파일러는 cat 변수를 string으로 추론할 것입니다.

위 코드를 타입 단언 형식으로는 아래와 같이 작성할 수 있습니다.

type AnimalType = "cat" | "dog";

let cat = "cat" as AnimalType;

타입 단언은 컴파일타임에서만 타입을 변경하기 때문에 타입 에러는 잡아주지만, 타입 캐스팅과는 다르게 실제로 프로그램 실행 시에 발생하는 런타임 에러를 방지하지는 않습니다. 정말 내가 컴파일러보다 타입을 잘 알고 있다고 확신할 때에만 쓰는 것이 바람직합니다.

type AnimalType = "cat" | "dog";

let cat: AnimalType = "cat";

이런 상황에서는, 변수의 타입을 표기하고 싶을 것이기 때문에 타입 표기(Type Annotation)로 사용하는 것이 더 적절해 보입니다.

class Person {
  name!: string;
  type!: "programmer" | "author";
}

class Programmer extends Person {
  language!: string;
}

class Author extends Person {
  books: string[] = [];
}

const introduce = (person: Person) => {
  if (person.type === "programmer") {
    console.log(`${person.name} is a programmer and uses ${person.language}`);
    // Property 'language' does not exist on type 'Person'.
  } else if (person.type === "author") {
    console.log(
      `${person.name} is an author and wrote ${person.books.join(", ")}`);
    // Property 'books' does not exist on type 'Person'.
  }
};

Person의 type에 따라 이 사람이 프로그래머인지, 작가인지 우리는 알 수 있지만, 타입스크립트 컴파일러는 알 수 없습니다.

const introduce = (person: Person) => {
  if (person.type === "programmer") {
    console.log(`${person.name} is a programmer and uses ${(person as Programmer).language}`); 
  } else if (person.type === "author") {
    console.log(
      `${person.name} is an author and wrote ${(person as Author).books.join(", ")}` 
    );
  }
};

이렇게 타입 단언을 사용하여, 이 person이 Programmer 혹은 Author라는 것을 강제로 선언할 수 있습니다. 하지만 코드가 복잡해질 경우 일일이 타입 단언을 작성하기가 번거롭습니다. 타입 가드(Type Guard)는 이런 상황에서 사용할 수 있습니다.

class Person {
  name!: string;
  isProgrammer(): this is Programmer {
    return this instanceof Programmer;
  }
  isAuthor(): this is Author {
    return this instanceof Author;
  }
}

class Programmer extends Person {
  language!: string;
}

class Author extends Person {
  books: string[] = [];
}

const introduce = (person: Person) => {
  if (person.isProgrammer()) {
    console.log(`${person.name} is a programmer and uses ${person.language}`);
  } else if (person.isAuthor()) {
    console.log(
      `${person.name} is an author and wrote ${person.books.join(", ")}`
    );
  }
};

 

반응형

댓글