"모양이 다른 여러 상태를 하나의 객체에 선택 속성으로 쑤셔 넣지 마. 각 상태가 자기 필드를 갖게 해."
공통 판별 필드
판별 가능한 유니언은 모든 변형이 같은 이름의 필드를 갖고, 각 변형에서 서로 다른 리터럴 값을 사용하는 객체 유니언이야. 원, 사각형, 직사각형이 모두 kind를 가지되 값이 'circle', 'square', 'rect'로 갈리는 식이지.
shape.kind === 'circle'을 확인하면 컴파일러는 shape 전체가 원 변형이라고 알아. radius를 안전하게 읽고, 그 분기에서 side를 읽으면 오류를 보여 줘. 한 필드의 증거가 객체 전체의 모양을 좁힌다.
불가능한 상태를 만들 수 없게 해
로딩 상태를 { loading: boolean; data?: T; error?: Error } 하나로 나타내면 loading이 true인데 data와 error가 동시에 있는 조합도 타입상 가능해. 판별 유니언으로 idle, loading, success, error를 각각 나누면 각 상태에 필요한 필드만 존재하고 불가능한 조합은 만들 수 없어.
좋은 타입은 잘못된 값을 잡는 데서 끝나지 않아. 잘못된 상태를 표현할 문법 자체를 없애. 상태 기계, 이벤트, 명령, API 결과에서 이 패턴이 반복되는 이유야.
판별 필드 이름은 일관되게
kind, type, status, tag 가운데 도메인에 맞는 이름을 골라. 구체 이름보다 프로젝트 전체의 일관성이 더 중요해. 값의 타입은 넓은 string이 아니라 정확한 리터럴이어야 좁히기가 작동한다.
switch와 함께 읽기 좋아
변형이 둘이면 if도 충분하지만 수가 늘면 switch가 전체 목록을 한눈에 보여 줘. 각 case 안에서는 전용 필드가 열리고, 마지막에 assertNever를 두면 새 변형을 추가했을 때 빠진 처리 지점을 컴파일러가 찾아 준다.
판별 필드 이름은 프로젝트 안에서 통일해. React reducer에서는 type, 함수형 언어에서 옮겨 온 코드에서는 tag가 자주 보이고, 도메인 모델에서는 JavaScript의 다른 type 의미와 겹치지 않도록 kind를 고르기도 해.