타입스크립트 교재 · 5편 / 20편

유니온과 인터섹션 — A | B 와 A & B

"이것 또는 저것" 과 "이것이면서 저것" — 가장 자주 쓰는 두 합성.

기초읽는 시간 7분2026-05-17
A | B (벤 다이어그램 합집합)와 A & B (교집합) 도식

입문 파트가 끝났습니다. 5편부터는 기초 파트 — 본격적으로 "TS 다운" 타입 합성을 다룹니다. 그 첫 번째가 유니온(|)인터섹션(&)입니다. 둘은 거의 모든 실전 타입 설계의 출발점이에요.

유니온 — "이것 또는 저것"

// 변수가 string 또는 number 중 하나
let id: string | number;
id = "abc";      // OK
id = 42;         // OK
id = true;       // ❌

// 함수 매개변수도 유니온
function format(input: string | number): string {
  // 여기서는 input 이 string|number — 양쪽 다에 있는 메서드만 호출 가능
  return String(input);
}

유니온은 "가능한 타입의 집합"입니다. 사용하려면 "지금 무엇인지" 좁혀야 합니다 — 그게 다음 절의 narrowing.

좁히기(narrowing) — 유니온을 다루는 핵심

function format(input: string | number): string {
  if (typeof input === "string") {
    return input.toUpperCase();   // ✅ 여기서는 string 확정
  }
  return input.toFixed(2);        // ✅ 여기서는 number 확정
}

TS 는 typeof·instanceof·in·=== 같은 검사를 보면 흐름에 따라 타입을 좁힙니다. 이걸 제어 흐름 분석(control flow analysis) 이라고 부르는데, IDE 자동완성이 if 안과 밖에서 달라지는 비결입니다.

좁히는 도구예시언제
typeoftypeof x === "string"primitive
instanceoferr instanceof Error클래스 인스턴스
in"name" in obj객체 속성 유무
===shape.kind === "circle"리터럴 비교 (구분 가능 유니온)
사용자 정의function isUser(x): x is User14편

구분 가능 유니온 — 실전의 보석

// 각 멤버에 "꼬리표"(discriminant) 가 있는 유니온
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number }
  | { kind: "rect";   w: number; h: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.radius ** 2;   // s 는 circle 로 좁혀짐
    case "square": return s.side ** 2;
    case "rect":   return s.w * s.h;
  }
}

실전에서 가장 많이 쓰는 패턴. API 응답의 success/error 분기, 리덕스 액션, 상태 머신 — 거의 모두 구분 가능 유니온으로 모델링합니다. kind / type / status 같은 literal 필드 하나로 나머지 모양이 결정되니까요.

인터섹션 — "이것이면서 저것"

type Named   = { name: string };
type Aged    = { age: number };
type Person  = Named & Aged;     // { name; age }

const p: Person = { name: "준성", age: 39 };

// 함수 합치기 — mixin 패턴
type Loggable    = { log(): void };
type Serializable = { toJSON(): string };
type Service = Loggable & Serializable;

// 함수 시그니처 합성
type Add  = (a: number, b: number) => number;
type Bind = (this: void) => void;
type API  = Add & Bind;          // 같은 함수가 두 호출 시그니처를 다 갖는다

인터섹션은 "두 모양을 모두 만족" 입니다. 객체 타입을 결합할 때 가장 자주 쓰고, 인터페이스의 extends 와 거의 같은 역할을 합니다.

유니온 vs 인터섹션 — 직관과 반대인 한 가지

"| 는 OR 라서 더 넓다? 아니요." 타입에서는 거꾸로입니다.

· A | B값의 집합은 더 넓지만, 사용할 수 있는 속성은 더 좁다(양쪽에 공통인 것만).

· A & B값의 집합은 더 좁지만, 사용할 수 있는 속성은 더 넓다(양쪽 합).

type Dog = { bark(): void };
type Cat = { meow(): void };

let pet: Dog | Cat = { bark(){} };
pet.bark();   // ❌ 'Cat' 에는 bark 가 없으니까 안전하게 막힘
pet.meow();   // ❌

let monster: Dog & Cat = { bark(){}, meow(){} };
monster.bark();  // ✅
monster.meow();  // ✅

리터럴 유니온 — enum 의 대체

// 7편에서 다룰 enum 의 가벼운 대안
type Theme  = "light" | "dark" | "auto";
type Status = 200 | 404 | 500;

function setTheme(t: Theme) { ... }
setTheme("light");   // OK
setTheme("blue");    // ❌ 컴파일 시점에 차단

대부분의 상태값·테마·HTTP 코드 등은 enum 보다 리터럴 유니온이 가볍고 다루기 좋습니다. 7편에서 enum 과 비교.

6편 — 제네릭 입문

<T> 한 글자의 힘. 왜 제네릭이 라이브러리 코드의 핵심인지.

📚 쉽게 배우는 타입스크립트 교재
이전: 4편 interface vs type · 현재: 5편 (기초 시작) · 다음 → 6편 제네릭 · 진행: 5/20

© 2026 주나이테크(주) @JUNAITECH