iBetter Books
수정

Ch 05. 유니온과 인터섹션

|& 두 연산자로 타입을 조합합니다. 판별 유니온 패턴까지 맛봅니다.


유니온 타입 (|)

"이 타입 또는 저 타입" — 합집합입니다.

// 파일: src/union-basic.tstype StringOrNumber = string | number;function stringify(value: StringOrNumber): string {  return String(value);}stringify("hello");  // OKstringify(42);       // OKstringify(true);     // Error: Argument of type 'boolean' is not assignable// null 허용 패턴type Nullable<T> = T | null;type MaybeString = Nullable<string>;  // string | nullfunction getUsername(id: number): MaybeString {  return id === 0 ? null : "Alice";}

유니온 타입 좁히기 (맛보기)

유니온 타입은 공통 프로퍼티만 직접 접근할 수 있습니다.

// 파일: src/union-narrowing.tsfunction formatId(id: string | number): string {  // id.toFixed()  // Error — string에는 toFixed가 없음  // id.toUpperCase()  // Error — number에는 없음  // typeof로 좁히기  if (typeof id === "string") {    return id.toUpperCase();  // OK — string 확정  }  return id.toFixed(0);       // OK — number 확정}

타입 좁히기 전체는 PART 03에서 다룹니다.


리터럴 타입

특정 값 자체가 타입이 됩니다.

// 파일: src/literal-types.tstype Direction = "north" | "south" | "east" | "west";type Coin = 1 | 5 | 10 | 50 | 100 | 500;type Toggle = true | false;  // boolean과 동일function move(dir: Direction, steps: number): void {  console.log(`moving ${dir} by ${steps}`);}move("north", 3);  // OKmove("up", 3);     // Error: Argument of type '"up"' is not assignable to type 'Direction'// 함수 반환 타입으로도 활용function compare(a: number, b: number): -1 | 0 | 1 {  if (a < b) return -1;  if (a > b) return 1;  return 0;}

인터섹션 타입 (&)

"이 타입이면서 저 타입" — 교집합이 아니라 모든 프로퍼티를 합칩니다.

// 파일: src/intersection.tsinterface HasName {  name: string;}interface HasAge {  age: number;}interface HasEmail {  email: string;}type Person = HasName & HasAge;type Contact = HasName & HasEmail;type FullProfile = HasName & HasAge & HasEmail;const person: Person = { name: "Alice", age: 30 };const contact: Contact = { name: "Bob", email: "[email protected]" };const profile: FullProfile = {  name: "Carol",  age: 25,  email: "[email protected]",};

인터섹션은 믹스인 패턴이나 여러 인터페이스를 합칠 때 씁니다.


인터섹션 실무 패턴 — Mixin

// 파일: src/intersection-mixin.ts// 공통 응답 메타데이터type ApiMeta = {  requestId: string;  timestamp: number;};// 각 엔드포인트별 데이터type UserData = {  id: number;  name: string;};type PostData = {  id: number;  title: string;  content: string;};// API 응답 = 데이터 + 공통 메타type UserResponse = UserData & ApiMeta;type PostResponse = PostData & ApiMeta;function wrapResponse<T>(data: T): T & ApiMeta {  return {    ...data,    requestId: crypto.randomUUID(),    timestamp: Date.now(),  };}

판별 유니온 (Discriminated Union) 맛보기

서로 다른 형태의 객체를 하나의 타입으로 다룰 때 핵심 패턴입니다.

// 파일: src/discriminated-union.ts// 공통 판별자(discriminant) 프로퍼티를 가진 타입들interface Circle {  kind: "circle";  // 리터럴 타입  radius: number;}interface Rectangle {  kind: "rectangle";  width: number;  height: number;}interface Triangle {  kind: "triangle";  base: number;  height: number;}type Shape = Circle | Rectangle | Triangle;function area(shape: Shape): number {  switch (shape.kind) {    case "circle":      return Math.PI * shape.radius ** 2;  // shape: Circle    case "rectangle":      return shape.width * shape.height;   // shape: Rectangle    case "triangle":      return (shape.base * shape.height) / 2;  // shape: Triangle  }}console.log(area({ kind: "circle", radius: 5 }));        // ~78.5console.log(area({ kind: "rectangle", width: 4, height: 6 }));  // 24

kind 같은 리터럴 타입 프로퍼티가 판별자 역할을 합니다. TypeScript는 switch의 각 case에서 정확한 타입을 알게 됩니다.

판별 유니온 심화 (완전성 검사, exhaustive check)는 PART 03에서 다룹니다.


유니온 vs 인터섹션 비교

// 파일: src/union-vs-intersection.tstype A = { x: number };type B = { y: string };// 유니온 — A이거나 B (공통 프로퍼티만 접근 가능)type AorB = A | B;const v1: AorB = { x: 1 };           // OKconst v2: AorB = { y: "hi" };         // OKconst v3: AorB = { x: 1, y: "hi" };  // OK (A와 B 모두 만족)// v1.x — 안전하지 않음, v1이 B일 수도 있으므로// 인터섹션 — A이면서 B (모든 프로퍼티 접근 가능)type AandB = A & B;const v4: AandB = { x: 1, y: "hi" };  // 반드시 둘 다 있어야 함console.log(v4.x, v4.y);              // OK

정리

  • | — 여러 타입 중 하나, 공통 프로퍼티만 바로 접근 가능합니다.
  • & — 모든 타입의 프로퍼티를 합침, 믹스인에 유용합니다.
  • 리터럴 타입은 값 자체를 타입으로 사용합니다.
  • 판별 유니온은 kind 같은 공통 리터럴 프로퍼티로 타입을 좁힙니다.