TypeScript/비동기/Lesson 07
에러 처리 심화 — Discriminated Union + Result<T, E> 패턴
40분·theory
이 챕터
7/7
TypeScript
에러 처리 심화 — Discriminated Union + Result
2. Result
에러 처리 심화 — Discriminated Union + Result 패턴
💡 왜 배워야 할까요? — 에러를 '값' 으로 다루면 더 안전하다
🎯
throw/catch 는 흐름이 점프합니다 — 호출자가 어떤 에러를 잡아야 할지 시그니처만 봐선 모릅니다.
💼
Result 패턴은 에러를 **반환값** 으로 다룹니다. 함수 시그니처에 가능한 에러 종류가 박혀 있어 누락이 컴파일 시점에 드러납니다.
⚡
Discriminated Union(`type Result = Ok | Err`) 으로 모델링하면 호출부가 `if (result.ok)` 같이 자연스럽게 분기.
🔗
Rust·Go·Kotlin Result/Either 패턴과 같은 사고방식 — 함수형 프로그래밍의 표준 도구.
📈
`never` 타입으로 'exhaustive check'(모든 경우 처리했는지) 를 컴파일러가 검증해줍니다.
🏢 실무에서는
Next.js Server Action 의 반환 타입을 `Promise>` 같이 박으면, 클라이언트 컴포넌트가 성공/실패 분기를 빠짐없이 처리하게 됩니다. throw 로 에러가 흐르면 클라이언트는 'try/catch 를 어디서 감쌌어야 하지' 같은 고민을 해야 하지만, Result 로 반환하면 컴파일러가 그 고민을 대신해줍니다.
Discriminated Union · Result · Exhaustive Check
1. Discriminated Union — 태그 필드로 분기되는 타입
태그(kind) 필드 값을 좁히면 객체 모양 전체가 좁혀집니다.
2. Result 패턴
호출부에서 에러 처리를 잊으면 컴파일이 막아준다 — r.value 를 if 없이 바로 쓰면 거부.
3. never 로 Exhaustive Check (망라 확인)
Event 에 새 종류를 추가했는데 switch 에 안 적었으면, e 가 never 가 아니라서 _exhaustive: never 할당이 컴파일 거부 → 처리 누락을 컴파일 시점에 발견.
4. throw vs Result — 언제 무엇을?
throw 는 '비정상' 용, Result 는 '예상되는 실패' 용.
💡 💡 Result 패턴 실전 가이드
1. Result 는 라이브러리 없이 만든다 — 30줄이면 끝
2. 에러도 Discriminated Union 으로 분류
에러 종류마다 추가 정보(field·max) 를 정확한 위치에 박는다.
3. never 로 exhaustive check 강제
4. Result 와 throw 의 경계
예측 가능한 실패(검증 실패·404·인증) → Result. 예측 불가 버그(null pointer·OOM) → throw + 글로벌 핸들러.
5. async + Result
예상된 실패는 Result, 예상 못한 에러는 throw 로 위로.
⚡ 직접 실행해보기 — Result 패턴
에러를 반환값으로 처리하는 흐름을 체감합니다.
✏️ JS 코드
📟 콘솔 출력
▶ 실행 버튼을 눌러보세요
⚠️ 브라우저 샌드박스에서 실행 — console.log()만 지원, alert/fetch 불가
확인 퀴즈
Discriminated Union 에 `default: const _: never = x;` 패턴을 두는 이유는?
먼저 읽으면 좋은 개념: 에러 처리 — catch 의 unknown 좁히기
다음 추천: React 소개