dev.syw

유니온·리터럴 타입과 typeof·in·instanceof를 이용한 narrowing, 판별 유니온을 다룬다.

유니온과 타입 좁히기

하나의 값이 여러 타입 중 하나일 수 있을 때 유니온 타입을 씁니다. 그리고 그 값을 안전하게 다루려면 "지금 어떤 타입인지" 좁혀 가는 narrowing 이 필요합니다.

학습 목표

  • 유니온 타입을 선언하고 사용한다.
  • typeof, in, instanceof 로 타입을 좁힌다.
  • 판별 유니온(discriminated union)을 설계한다.
  • 모든 경우를 처리했는지 검사한다.

유니온 타입

| 로 "이거 또는 저거"를 표현합니다.

let id: string | number;
id = 'abc'; // OK
id = 123;   // OK
id = true;  // ❌ string도 number도 아님

유니온 값은 공통으로 가능한 동작만 바로 쓸 수 있습니다.

function printId(id: string | number) {
  console.log(id.toUpperCase()); // ❌ number엔 toUpperCase가 없음
}

그래서 타입을 좁혀야 합니다.

typeof 로 좁히기

원시 타입은 typeof 로 구분합니다. 조건문 안에서 TypeScript가 자동으로 타입을 좁혀 줍니다.

function printId(id: string | number) {
  if (typeof id === 'string') {
    console.log(id.toUpperCase()); // 여기선 id가 string
  } else {
    console.log(id.toFixed(2));    // 여기선 id가 number
  }
}

in 으로 좁히기

객체에 특정 속성이 있는지로 구분할 때 in 을 씁니다.

type Bird = { fly: () => void };
type Fish = { swim: () => void };

function move(animal: Bird | Fish) {
  if ('fly' in animal) {
    animal.fly();   // Bird
  } else {
    animal.swim();  // Fish
  }
}

instanceof 로 좁히기

클래스 인스턴스는 instanceof 로 구분합니다.

function format(value: Date | string) {
  if (value instanceof Date) {
    return value.toISOString(); // Date
  }
  return value.trim();          // string
}
방법용도
typeof원시 타입(string/number/boolean...)
in객체의 속성 존재 여부
instanceof클래스 인스턴스

판별 유니온

객체 유니온을 다루는 가장 강력한 패턴입니다. 각 타입에 공통 리터럴 필드(판별자) 를 두면, 그 값으로 안전하게 구분할 수 있습니다.

type Circle = { kind: 'circle'; radius: number };
type Square = { kind: 'square'; size: number };
type Shape = Circle | Square;

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2; // Circle로 좁혀짐
    case 'square':
      return shape.size ** 2;             // Square로 좁혀짐
  }
}

💡 TIPkind, type, tag 같은 리터럴 필드를 판별자로 두는 것이 판별 유니온의 핵심입니다. switch 와 궁합이 아주 좋습니다.

모든 경우 처리 확인

새 타입을 유니온에 추가했는데 처리를 빠뜨리면 위험합니다. never 를 이용하면 처리 안 된 경우를 컴파일 단계에서 잡을 수 있습니다.

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.size ** 2;
    default:
      const _exhaustive: never = shape; // 새 타입 추가 시 여기서 오류
      return _exhaustive;
  }
}

⚠️ 주의 — 나중에 Triangle 같은 타입을 Shape 에 추가하면, 위 default 에서 즉시 타입 오류가 납니다. 이것이 처리 누락을 막아 주는 안전장치입니다.

요약

  • 유니온 A | B 는 여러 타입 중 하나임을 나타낸다.
  • typeof/in/instanceof 로 타입을 좁혀 안전하게 쓴다.
  • 공통 리터럴 필드를 둔 판별 유니온은 switch 와 잘 맞는다.
  • never 로 모든 경우를 처리했는지 컴파일 단계에서 검사할 수 있다.

댓글 0

TypeScript” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.