"TypeScript 의 가장 유용한 단일 패턴. 한 번 보면 매일 쓸 자리 찾게 돼."
Discriminated union 이 뭐
Discriminated union 은 모든 variant 가 그 variant 에 고유한 값의 literal 타입 property — discriminator — 담는 object 타입의 union. Compiler 가 너가 체크할 때 discriminator 써서 전체 object narrow.
고전 예시: 도형.
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number }
| { kind: 'rect'; w: number; h: number };
모든 variant 가 그 variant 에 고유한 literal 문자열 값의 kind 필드. if (shape.kind === 'circle') 체크하면 compiler 가 shape 를 circle variant 로 narrow — 그리고 안전하게 shape.radius 읽을 수 있어.
왜 이 패턴이 너무 좋아
Discriminated union 이 실제 도메인 개념 깔끔하게 모델링: 상태 (idle/loading/done/error), event (click/keypress/scroll), API 응답 (success/error), 도형 (circle/square/rect). 데이터가 '이거 OR 저거, 어느 거냐에 따라 모양 달라' 인 어디든 discriminated union 이 옳은 모델.
결합 효과: compiler 가 variant 구별 유지, narrowing 이 if/switch 안에서 자동 발생, exhaustiveness 가 never 통해 강제 가능 (다음 lesson). 패턴이 2 variant 에서 20+ variant 까지 명확성 안 잃고 scale.
Discriminator 필드 관례
Discriminator 필드는 관례적으로 kind, type, tag 로 이름 붙음. 하나 골라서 codebase 전체에 일관되게 써. React 의 reducer 패턴이 type 써. 함수형-언어 port 자주 tag 써. 도메인-specific 프로젝트가 JavaScript 의 built-in type 의미와 충돌 피하려 kind 골라. 선택은 스타일 — 구체 이름보다 일관성 더 중요.
피파의 고백
kind 나 status 로 tag. 패턴이 너무 default 라서 뭐가 안 그렇면 알아차려: '왜 이게 discriminated union 대신 optional 필드 가진 plain object 야?' 보통은 그래야 했어.