타입 가드

boyeonJ·2023년 8월 22일
0

TypeScript

목록 보기
10/12
post-thumbnail

타입가드란?

타입 가드(Type Guard)는 TypeScript에서 변수의 타입을 좁히는 데 사용되는 메커니즘입니다. TypeScript는 정적 타입 언어로서 변수의 타입을 컴파일 타임에 결정합니다. 하지만 때로는 런타임에서 변수의 타입이 더 구체적이거나 제한적일 수 있습니다. 이런 경우를 다루기 위해 타입 가드를 사용합니다.

타입 가드를 사용하면 변수의 타입을 더 구체적인 타입으로 좁히거나 확인할 수 있습니다. 이를 통해 타입 시스템이 변수의 타입을 정확히 추론할 수 있게 되며, 코드 안전성과 가독성을 향상시킬 수 있습니다.

가장 일반적인 타입 가드 형태는 typeof, instanceof, in, 그리고 사용자 정의 함수(타입 가드 함수)입니다.

타입단언으로도 타입을 좁힐 수 있지만 실행시점에서의 에러가 발생할 가능성이 있으며 타입단언 문법을 불필요하게 반복적으로 사용하여야 한다는 단점이 있습니다. 따라서 타입단언보다는 타입가드를 사용하는것이 권장됩니다.


타입가드 문법

타입가드 문법으로는 typeof, instanceof, in 등이 있습니다. 이 문법은 자바스크립트의 문법이며 이를 활용하여 타입 가드를 구현할 수 있습니다.

typeof A: A 타입을 문자열로 반환
A instanceof B: B의 프로토타입 체인에 A가 포함되었는지 boolean 반환 (A가 B의 인스턴스인지 확인)
a in A: A의 속성중에 a가 있는지 boolean 반환

typeof를 사용한 타입 가드

function getNumber(value: string | number): void {
  if (typeof value === "string") {
    console.log(value.length); 
  } else {
    console.log(value); 
  }
}

instanceof를 사용한 타입 가드

class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Animal {
  type: string;
  constructor(type: string) {
    this.type = type;
  }
}

function printDetails(obj: Person | Animal): void {
  if (obj instanceof Person) {
    console.log(obj.name); // obj는 Person으로 추론됨
  } else {
    console.log(obj.type); // obj는 Animal로 추론됨
  }
}

instanceof를 사용한 타입 가드

만약 아래 코드의 id와 같이 공통된 속성을 in 타입가드로 활용하게 되면 타입가드의 역할을 하지 못한다.

interface Book {
  id: number;
  rank: number;
}

interface OnlineLecture {
  id: string;
  url: string;
}

function learnCourse(material: Book | OnlineLecture) : number | string {
  if (rank in material) {
    return material.rank; // material는 Book 추론됨
  } else {
    return material.url; // obj는 OnlineLecture로 추론됨
  }
  
  if(id in material){
  	console.log(material.id); //material.id는 number|string으로 추론이 되어, 타입 가드 역할 못함 못하게 된다.(자동완성 기능 사용 불가)
  }
}

타입 가드 함수(사용자 정의 함수를 사용한 타입 가드)

이 함수는 문법이나 구현된 함수가 아니라 사용자가 직접 타입을 구별하기 위한 함수를 만드는 것을 의미합니다. is 문법을 활용합니다.

두개 interface가 공통으로 id라는 속성을 가지게 된다면 in으로는 구별할 수 없습니다. 따라서 타입 가드 함수를 통해 좀 더 구체적으로 타입을 구별할 수 있습니다.

interface Car {
  brand: string;
  speed: number;
}

function isCar(vehicle: any): vehicle is Car {
  return "brand" in vehicle && "speed" in vehicle;
}

function displayVehicleInfo(vehicle: Car | { type: string }): void {
  if (isCar(vehicle)) {
    console.log(vehicle.brand, vehicle.speed); // vehicle은 Car로 추론됨
  } else {
    console.log(vehicle.type); // vehicle은 { type: string }으로 추론됨
  }
}

구별된 유니언 타입

속성의 타입은 타입(number, string...) 뿐만 아니라 실제 값으로도 정의할 수 있습니다. 이럴 경우 속성의 유무가 아닌 실제 값으로 구분을 하여 타입을 구별해야 합니다.

type Shape = "square" | "circle";

interface Square {
  kind: "square";
  size: number;
}

interface Circle {
  kind: "circle";
  radius: number;
}

function calculateArea(shape: Shape, data: Square | Circle): number {
  if (shape === "square") {
    return data.size * data.size;
  } else {
    return Math.PI * data.radius * data.radius;
  }
}

0개의 댓글