diff --git "a/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.2_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\355\203\200\354\236\205_\352\260\200\353\223\234/seulgi.md" "b/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.2_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\355\203\200\354\236\205_\352\260\200\353\223\234/seulgi.md"
index 3beced8..a9f75d9 100644
--- "a/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.2_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\355\203\200\354\236\205_\352\260\200\353\223\234/seulgi.md"
+++ "b/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.2_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\355\203\200\354\236\205_\352\260\200\353\223\234/seulgi.md"
@@ -1 +1,240 @@
-
+# 타입 좁히기 - 타입 가드
+
+타입 좁히기는 변수 또는 표현식의 타입 범위를 더 작은 범위로 좁혀나가는 과정이다.
+더 정확하고 명시적인 타입 추론을 할 수 있고, 복잡한 타입을 작은 범위로 축소하여 타입 안정성을 높일 수 있다.
+
+## 1) 타입 가드에 따라 분기 처리하기
+
+타입스크립트에서 분기 처리는 **조건문과 타입 가드를 활용**한다.
변수나 표현식의 타입 범위를 좁혀 다양한 상황에 따라 다른 동작을 수행하는 것이다.
+
+타입 가드는 **런타임에 조건문을 사용해 타입을 검사해 타입 범위를 좁히는 기능**이다.
+
+### 여러 타입을 할당할 수 있는 스코프에서 분기 처리하려면?
+
+여러 타입을 할당할 수 있는 스코프(타입스크립트에서 스코프는 변수와 함수 등 식별자가 유효한 범위,
+
즉 변수와 함수를 선언하거나 사용할 수 있는 영역)에서 특정 타입을 조건으로 만들어 분기 처리하고 싶을 때가 있다.
+
+> 이 때, 여러 타입을 할당할 수 있다는 것은 변수가 유니온 타입 또는 any 타입 등과 같이 여러 가지 타입을 받을 수 있다는 것을 말한다.
+
+### 함수가 A | B 타입의 매개변수를 받을 때,
인자 타입이 A 또는 B일 때를 구분해서 로직을 처리하고 싶다면?
+
+if 문을 사용해서 처리한다해도 컴파일 시 타입 정보는 모두 제거되기 때문에 런타임에 존재하지 않는다.
+
+> 컴파일해도 타입 정보가 사라지지 않는 방법을 사용해야 하고, 특정 문맥 안에서 타입스크립트가 해당 변수를 타입 A로 추론하도록 유도하면서 런타임에서도 유효한 방법이 필요하다!
+
+### 이 때 사용하는 것이 "타입 가드"!
+
+1. 자바스크립트 연산자를 사용한다.
+2. 사용자 정의 타입 가드로 사용한다.
+
+위의 두 방법으로 타입 가드를 사용할 수 있다.
+
+### 자바스크립트 연산자를 활용한 타입 가드에 대해 알아보자.
+
+- typeof, instanceof, in과 같은 연산자를 사용한다.
+- 제어문으로 특정 타입 값을 가질 수밖에 없는 상황을 유도해 자연스럽게 타입을 좁히는 방식이다.
+
+> 런타임에 유효한 타입 가드를 만들기 위해 자바스크립트 연산자를 사용한다.
+
+
+
+
+## 2) 원시 타입을 추론할 때: typeof 연산자 활용하기
+
+- typeof 연산자를 활용하면 원시 타입에 대해 추론할 수 있다.
+- typeof A === B를 조건으로 분기 처리하면 해당 분기 내에서 A의 타입이 B로 추론된다.
+- 다만, typeof는 자바스크립트 타입 시스템만 대응 가능하다.
+- null, 배열 타입 등 object 타입이 판별되는 등 복잡한 타입을 검증하기에는 한계가 있다.
+
+> 따라서, typeof 연산자는 주로 원시 타입을 좁히는 용도로만 사용하는 것을 권장한다.
+
+### typeof 연산자를 사용해 검사할 수 있는 타입들
+
+- string
+- number
+- boolean
+- undefined
+- object
+- function
+- bigint
+- symbol
+
+```ts
+const replaceHyphen: (date: string | Date) => string | Date = (date) => {
+ if (typeof date === "string") {
+ return date.replace(/-/g, "/");
+ }
+
+ return date;
+};
+```
+
+
+
+
+## 3) 인스턴스화된 객체 타입을 판별할 때: instanceof 연산자 활용하기
+
+selected 매개변수가 Date인지 검사 후 Range 타입의 객체를 반환할 수 있도록 분기처리하는 예시를 보자.
+
+```ts
+interface Range {
+ start: Date;
+ end: Date;
+}
+
+interface DatePickerProps {
+ selectedDates?: Date | Range;
+}
+
+const DatePicker = ({ selectedDates }: DatePickerProps) => {
+ const [selected, setSelected] = useState(convertToRange(selectedDates));
+};
+
+export function convertToRange(selected?: Date | Range): Range | undefined {
+ return selected instanceof Date
+ ? { start: selected, end: selected }
+ : selected;
+}
+```
+
+- instanceof 연산자는 인스턴스화된 객체 타입을 판별하는 타입 가드로 사용한다.
+- A instanceof B 형태로 사용한다.
+- A에는 타입을 검사할 대상 변수, B에는 특정 객체의 생성자가 들어간다.
+
+> **instanceof?**
+> instanceof는 A의 프로토타입 체인에 생성자 B가 존재하는지를 검사해
존재한다면 true, 그렇지 않다면 false를 반환한다.
+
+### A의 프로토타입 속성 변화에 따라 instanceof 연산자의 결과가 달라질 수 있다.
+
+```ts
+const onKeyDown = (event: React.KeyboardEvent) => {
+ if (event.target instanceof HTMLElement && event.key === "Enter") {
+ event.target.blur();
+ onCTAButtonClick(event);
+ }
+};
+```
+
+
+
+
+## 4) 객체의 속성이 있는지 없는지에 따른 구분: in 연산자 활용하기
+
+- in연산자는 객체에 속성이 있는지 확인한 다음에 true 또는 false를 반환한다.
+- A in B의 형태로 사용한다.
+- A라는 속성이 B 객체에 존재하는지를 검사한다.
+- 프로토타입 체인으로 접근할 수 있는 속성이면 전부 true를 반환한다.
+
+### 프로토타입 체인으로 접근할 수 있는 속성이면 전부 true를 반환한다?
+
+```ts
+const obj = { a: 1 };
+
+console.log("a" in obj); // true (자기 자신의 속성)
+console.log("toString" in obj); // true (Object.prototype에 존재하는 속성)
+console.log("b" in obj); // false (존재하지 않는 속성)
+```
+
+> 객체 자체뿐만 아니라 프로토타입 체인까지 확인하는 연산자가 바로 in 연산자!
+
+- B 객체에 존재하는 속성에 undefined를 할당한다고 해서 false를 반환하지 않는다.
+- delete 연산자를 사용해 객체 내부에서 해당 속성을 제거해야만 false를 반환한다.
+
+```ts
+interface BasicDialogProps {
+ Title: string;
+ Body: string;
+}
+
+interface DialogWithCookieProps extends DialogProps {
+ cookieKey: string;
+ noForADay?: boolean;
+}
+
+export type DialogProps = BasicDialogProps | DialogWithCookieProps;
+```
+
+위의 Dialog 컴포넌트는 BasicDialogProps | DialogWithCookieProps를 유니온 타입으로 가지는 DialogProps를 props로 받는다.
+
+> Dialog 컴포넌트가 props로 받는 객체 타입이 둘 중에 어떤 타입이냐에 따라 렌더링하는 컴포넌트가 달라지게 하려면 props의 타입에 따라 렌더링하는 컴포넌트를 분기 처리하면 된다.
+
+### 위의 예제에서 두 객체 타입을 어떻게 분기 처리할까?
+
+- 자바스크립트 in 연산자는 런타임의 값만 검사한다.
+- 타입스크립트에서는 객체 타입에 속성이 존재하는지를 검사한다.
+
+```ts
+const Dialog: React.FC = (props) => {
+ if ("cookieKey" in props) {
+ return ;
+ }
+
+ return ;
+};
+```
+
+- 위의 예제는 두 객체 타입을 cookieKey라는 속성을 가졌는지 확인하는 조건을 만든다.
+- if문 스코프에서 타입스크립트는 props 객체를 cookieKey 속성을 갖는 객체 타입인 DialogWithCookieProps로 해석한다.
+- 얼리 리턴으로, if문 스코프 밖에 위치하는 return문의 props 객체는 BasicDialogProps 타입으로 해석한다.
+
+> 여러 객체 타입을 유니온 타입으로 가지고 있을 때 in 연산자를 사용해 속성의 유무에 따라 조건 분기를 할 수 있다.
+
+
+
+
+## 5) is연산자로 사용자 정의 타입 가드 만들어 활용하기
+
+직접 타입 가드 함수를 만들 수 있다. 해당 방식의 타입 가드는 반환 타입이 타입 명제(type predicates)인 함수를 정의해 사용할 수 있다.
+
+- 타입 명제는 A is B 형식으로 작성한다.
+- A는 "매개변수 이름", B는 "타입"이다. ("매개변수" is "타입")
+- 참/거짓의 진릿값을 반환하면서 반환 타입을 타입 명제로 지정하게 되면 반환 값이 참일 때 A 매개변수의 타입을 B타입으로 취급한다.
+- 타입 명제는 함수의 반환 타입에 대한 타입 가드를 수행하기 위해 사용되는 특별한 형태의 함수다.
+
+### predicates?
+
+수학적으로 주어진 조건을 만족하는지 아닌지를 테스트하는 함수나 표현식을 의미한다.
+프로그래밍 컨텍스트에서는 보통 어떤 값을 입력으로 받아 Boolean 값을 반환하는 함수를 가리키는데 대부분 통용되는 용어다.
+
+```ts
+const isDestinationCode = (x: string): x is DestinationCode =>
+ destinationCodeList.includes(x);
+```
+
+1. `isDestinationCode` 함수는 string 타입의 x 매개변수가 `DestinationCode` 배열의 원소 중 하나인지를 검사해 `boolean`을 반환하는 함수이다.
+2. 함수의 반환 값을 `boolean`이 아닌 `x is DestinationCode`로 타이핑한다.
+3. 해당 타이핑으로 타입스크립트에게 이 함수가 사용되는 곳의 타입을 추론할 때 해당 조건을 타입 가드로 사용하도록 알려준다.
+
+### 반환 값의 타입이 boolean인 것과 비교해보자
+
+```ts
+const getAvailableDestinationNameList = async ():Promise => {
+const data = await AxiosRequest('get', '.../destinations');
+ const destinationNames = DestinationName[] = [];
+
+ data?.forEach((str) => {
+ if (isDestinationCode(str)) {
+ destinationNames.push(DestinationNameSet[str]);
+ }
+ });
+
+ return destinationNames;
+}
+```
+
+> isDestinationCode(str)의 반환 값에 is를 사용하지 않고 boolean이라고 하면 에러가 발생한다. 위의 if 문 내 isDestinationCodeList의 문자열 원소 인지 체크하고 맞으면 destinationNames에 push한다.
+
+### isDestinationCode의 반환 값 타이핑을 x is DestinationCode가 아닌
boolean으로 했다면 타입스크립트는 어떻게 추론할까?
+
+개발자는 if문 내부에서 str타입이 DestinationCode라는 걸 알 수 있는데 Array.inclueds를 해석할 수 있기 때문이다.
+
+하지만, 타입스크립트는 isDestinationCode 함수 내부에 있는 includes 함수를 해석해 타입 추론을 할 수 없다.
+
+> 타입스크립트는 if문 스코프의 str타입을 좁히지 못하고 string으로만 추론한다. destinationNames의 타입은 DestinationName[]이기 때문에 string타입의 str을 push할 수 없다는 에러가 발생한다.
+
+### 타입스크립트에게 반환 값에 대한 타입 정보를 알려주고 싶을 때 is를 사용할 수 있다!
+
+반환 값 타입을 x is DestinationCode로 알려줌으로써 타입스크립트는 if문 스코프의 str 타입을 DestinationCode로 추론할 수 있게 된다.
+
+
+
diff --git "a/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.3_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\354\213\235\353\263\204\355\225\240_\354\210\230_\354\236\210\353\212\224_\354\234\240\353\213\210\354\230\250/seulgi.md" "b/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.3_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\354\213\235\353\263\204\355\225\240_\354\210\230_\354\236\210\353\212\224_\354\234\240\353\213\210\354\230\250/seulgi.md"
index 3beced8..9ec90af 100644
--- "a/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.3_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\354\213\235\353\263\204\355\225\240_\354\210\230_\354\236\210\353\212\224_\354\234\240\353\213\210\354\230\250/seulgi.md"
+++ "b/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.3_\355\203\200\354\236\205_\354\242\201\355\236\210\352\270\260_\354\213\235\353\263\204\355\225\240_\354\210\230_\354\236\210\353\212\224_\354\234\240\353\213\210\354\230\250/seulgi.md"
@@ -1 +1,195 @@
-
+# 타입 좁히기 - 식별할 수 있는 유니온(Discriminated Unions)
+
+태그된 유니온(tagged union) 혹은 식별할 수 있는 유니온 타입(Discriminated Unions)은 타입 좁히기에 널리 사용되는 방식이다.
+
+## 1) 에러 정의하기
+
+유효성 에러가 발생하면 사용자에게 다양한 방식으로 에러를 보여주는 예시로 살펴보자.
+
+우아한 형제들에서는 "텍스트 에러", "토스트 에러", "얼럿 에러"로 분류한다. 이들 모두 유효성 에러로 에러 코드와 메시지를 가지고 있고 에러 노출 방식에 따라 추가로 필요한 정보가 있을 수 있다고 가정하자.
+
+```ts
+type TextError = {
+ code: string;
+ message: string;
+};
+
+type ToastError = {
+ code: string;
+ message: string;
+ toastShowDuration: number;
+};
+
+type AlertError = {
+ code: string;
+ message: string;
+ onConfirm: () => void;
+};
+
+type ErrorType = TextError | ToastError | AlertError;
+
+// 에러 타입의 유니온 타입을 원소로 하는 배열로 다양한 에러 객체를 관리 가능
+const errorArr: ErrorType[] = [
+ { code: "100", message: "텍스트 에러" },
+ { code: "200", message: "토스트 에러", toastShowDuration: 3000 },
+ { code: "300", message: "얼럿 에러", onConfirm: () => {} },
+];
+```
+
+### 위의 배열에 에러 타입별로 정의한 필드를 가지는 에러 객체가 포함되길 원한다면 어떨까?
+
+ToastError의 toastShowDuration 필드와 AlertError의 onConfirm 필드를 모두 가지는 객체에 대해서 에러를 받아야 한다.
+
+```ts
+const errorArr: ErrorType[] = [
+ { code: "100", message: "텍스트 에러" },
+ { code: "200", message: "토스트 에러", toastShowDuration: 3000 },
+ { code: "300", message: "얼럿 에러", onConfirm: () => {} },
+ {
+ code: "300",
+ message: "잘못된 에러",
+ toastShowDuration: 3000,
+ onConfirm: () => {},
+ },
+];
+```
+
+> 해당 코드 작성 시 자바스크립트는 덕타이핑 언어이기 때문에 별도의 타입 에러를 뱉지 않는다.
+
+## 2) 식별할 수 있는 유니온
+
+위의 예시처럼 타입 에러가 발생하지 않을 경우 개발 과정에서 무수한 에러 객체가 생겨날 위험성이 커진다.
+
+이럴 때 에러 타입을 구분할 방법이 필요한데 **각 타입이 비슷한 구조를 가지지만
+
서로 호환되지 않도록 만들어줘야 한다.**
+
+> "식별할 수 있는 유니온을 활용하는 것"이 그 방법!
+
+### 식별할 수 있는 유니온이란?
+
+타입 간의 구조 호환을 막기 위해 타입마다 구분할 수 있는 판별자(= 태그)를 달아주어 포함 관계를 제거하는 것이다.
+
+### 판별자의 개념으로 errorType 필드를 새로 정의해보자!
+
+```ts
+type TextError = {
+ type: "TEXT";
+ code: string;
+ message: string;
+};
+
+type ToastError = {
+ type: "TOAST";
+ code: string;
+ message: string;
+ toastShowDuration: number;
+};
+
+type AlertError = {
+ type: "ALERT";
+ code: string;
+ message: string;
+ onConfirm: () => void;
+}; // Object literal may only specify known properties, and 'toastShowDuration' does not exist in type 'AlertError'.
+```
+
+- 각 필드마다 다른 값을 가지도록 해 판별자를 달아준다.
+- 이 판별자에 의해 포함 관계를 벗어나게 된다.
+
+> 정확하지 않은 에러 객체에 대해 타입 에러가 발생하는 것을 확인할 수 있다.
+
+
+
+
+## 3) 식별할 수 있는 유니온의 판별자 선정
+
+식별할 수 있는 유니온을 사용할 때 주의할 점이 있다.
+
+식별할 수 있는 유니온의 판별자는 유닛 타입(unit type)으로 선언되어야 정상적으로 동작한다.
+
+### 유닛 타입이란?
+
+다른 타입으로 쪼개지지 않고 오직 하나의 정확한 값을 가지는 타입이다.
+
+- null, undefined, 리터럴 타입을 비롯해 true, 1 등 정확한 값을 나타내는 타입이다.
+- 반면, 다양한 타입을 할당할 수 있는 void, string, number와 같은 타입은 유닛 타입이 아니다.
+
+> **식별할 수 있는 유니온의 판별자로 사용할 수 있는 타입은?**
(1) 리터럴 타입이어야 한다,
(2) 판별자로 선정한 값에 적어도 하나 이상의 유닛 타입이 포함되어야 하며, 인스턴스화할 수 있는 타입은 포함되지 않아야 한다.
+
+### 인스턴스화할 수 있는 타입은 뭘까?
+
+TypeScript에서 **“인스턴스화할 수 있는 타입”** 이란 new 키워드를 사용하여 객체(인스턴스)를 생성할 수 있는 타입을 의미한다.
+
+### 인스턴스화할 수 있는 타입 목록
+
+| 타입 종류 | 인스턴스화 가능 여부 | 예시 |
+| ---------------------------- | -------------------- | ---------------------------------------- |
+| **클래스** | ✅ 가능 | `class Person {}` |
+| **생성자 함수** | ✅ 가능 | `function Animal() {}` |
+| **생성자 인터페이스** | ✅ 가능 | `interface A { new(): B }` |
+| **함수 타입 (`new()` 포함)** | ✅ 가능 | `type A = new (...args) => B` |
+| **내장 객체** | ✅ 가능 | `Date, RegExp, Map, Set, Promise, Error` |
+| **원시 타입** | ❌ 불가능 | `string, number, boolean, symbol` |
+| **일반 인터페이스** | ❌ 불가능 | `interface A { name: string; }` |
+| **객체 리터럴 타입** | ❌ 불가능 | `type A = { name: string }` |
+| **유니온 타입** | ❌ 불가능 | `type A = string \| number` |
+| **추상 클래스** | ❌ 불가능 | `abstract class A {}` |
+
+> “인스턴스화할 수 있는 타입”이란 new 키워드를 사용하여 객체를 생성할 수 있는 타입을 의미한다. 클래스, 생성자 함수, new() 시그니처가 있는 인터페이스, 생성자 함수 타입, 일부 내장 객체가 이에 해당한다.
+
+
+
+
+### 판별자의 타입에 따라 타입이 달라지는 예시를 알아보자.
+
+```ts
+interface A {
+ value: "a"; // unit type
+ answer: 1;
+}
+
+interface B {
+ value: string; // not unit type
+ answer: 2;
+}
+
+interface C {
+ value: Error; // instantiable type
+ answer: 3;
+}
+
+type Unions = A | B | C;
+
+function handle(param: Unions) {
+ param.answer; // 1 | 2 | 3
+
+ // "a"가 리터럴 타입으로 좁혀지나 string 타입에 포함도 되기 때문에 param은 A | B로 좁혀진다.
+ if (param.value === "a") {
+ param.answer; // 1 | 2 return;
+ }
+
+ // 유닛 타입이 아니거나 인스턴스화할 수 있는 타입일 경우 타입이 좁혀지지 않는다.
+ if (typeof param.value === "string") {
+ param.answer; // 1 | 2 | 3 return;
+ }
+
+ if (param.value instanceof Error) {
+ param.answer; // 1 | 2 | 3 return;
+ }
+
+ // 판별자가 answer일 때
+ param.value; // string | Error
+
+ // 판별자가 유닛 타입이므로 타입이 좁혀진다.
+ if (param.answer === 1) {
+ param.value; // "a"
+ }
+}
+```
+
+- 해당 코드에서는 판별자가 value일 떄 판별자로 선정한 값 중 "a"만 유일하게 유닛 타입이다.
+- **이때만 유닛 타입을 포함하고 있어 타입이 좁혀진다!**
+- 판별자가 answer일 때를 보면 판별자가 모두 유닛 타입이라 타입이 정상적으로 좁혀진다.
+
+
+
diff --git "a/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.4_Exhaustiveness_Checking\354\234\274\353\241\234_\354\240\225\355\231\225\355\225\234_\355\203\200\354\236\205_\353\266\204\352\270\260_\354\234\240\354\247\200\355\225\230\352\270\260/seulgi.md" "b/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.4_Exhaustiveness_Checking\354\234\274\353\241\234_\354\240\225\355\231\225\355\225\234_\355\203\200\354\236\205_\353\266\204\352\270\260_\354\234\240\354\247\200\355\225\230\352\270\260/seulgi.md"
index 3beced8..6f4e43e 100644
--- "a/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.4_Exhaustiveness_Checking\354\234\274\353\241\234_\354\240\225\355\231\225\355\225\234_\355\203\200\354\236\205_\353\266\204\352\270\260_\354\234\240\354\247\200\355\225\230\352\270\260/seulgi.md"
+++ "b/CH04_\355\203\200\354\236\205_\355\231\225\354\236\245\355\225\230\352\270\260_\354\242\201\355\236\210\352\270\260/4.4_Exhaustiveness_Checking\354\234\274\353\241\234_\354\240\225\355\231\225\355\225\234_\355\203\200\354\236\205_\353\266\204\352\270\260_\354\234\240\354\247\200\355\225\230\352\270\260/seulgi.md"
@@ -1 +1,95 @@
-
+# Exhaustiveness Checking으로 정확한 타입 분기 유지하기
+
+### Exhaustiveness?
+
+사전적으로 철저함, 완전함을 의미한다.
+
Exhaustiveness Checking은 모든 케이스에 대해 철저하게 타입을 검사하는 것이다.
+
타입 좁히기에 사용되는 패러다임 중 하나이다.
+
+때때로 모든 케이스에 대해 분기 처리를 해야 유지보수 측면에서 안전하다하는 상황에서
+
Exhaustiveness Checking을 통해 모든 케이스에 대한 타입 검사를 강제할 수 있다.
+
+## 1) 상품권
+
+선물하기 서비스에 있는 상품권 가격에 따라 상품권 이름을 반환해주는 함수가 있다.
+
+```ts
+type ProductPrice = "10000" | "20000";
+
+const getProductName = (productPrice: ProductPrice): string => {
+ if (productPrice === "10000") {
+ return "1만원";
+ }
+
+ if (productPrice === "20000") {
+ return "2만원";
+ } else {
+ return "기타";
+ }
+};
+```
+
+### 만약 상품권이 늘어나면 어떨까?
+
+```ts
+type ProductPrice = "10000" | "20000" | "5000";
+
+const getProductName = (productPrice: ProductPrice): string => {
+ if (productPrice === "10000") {
+ return "1만원";
+ }
+
+ if (productPrice === "20000") {
+ return "2만원";
+ }
+
+ if (productPrice === "5000") {
+ return "5천원"; // 조건 추가
+ } else {
+ return "기타";
+ }
+};
+```
+
+- ProductPrice 타입이 업데이트되었을 때 getProductName 함수도 업데이트 되어야 한다.
+
+### 업데이트된 타입에 맞게 함수를 수정하지 않아도 별도 에러가 발생하지 않을 수 있다!?
+
+이럴 때 필요한 것이 모든 타입에 대한 타입 검사를 강제해야 하는 것이다.
+
+```ts
+type ProductPrice = "10000" | "20000" | "5000";
+
+const getProductName = (productPrice: ProductPrice): string => {
+ if (productPrice === "10000") {
+ return "1만원";
+ }
+
+ if (productPrice === "20000") {
+ return "2만원";
+ } else {
+ exhaustiveCheck(productPrice); // Error!
+ return "기타";
+ }
+};
+
+const exhaustiveCheck = (param: never) => {
+ throw new Error("type error!");
+};
+```
+
+- exhaustiveCheck(productPrice)부분에 에러가 나는데 5000이라는 값에 대한 분기 처리를 하지 않아 발생한 것이다.
+
+> 이렇게 모든 케이스에 대한 타입 분기 처리를 해주지 않았을 때, 컴파일 타임 에러가 발생하게 하는 것을 Exhaustiveness Checking이라 한다.
+
+### exhaustiveCheck 함수를 자세히 알아보자.
+
+exhaustiveCheck 함수 매개변수를 never로 선언한 것은 매개변수로 그 어떤 값도 받을 수 없다는 것이다.
+
+만일 값이 들어오면 에러를 내뱉고, 이 함수를 타입 처리 조건문의 마지막 else문에 사용하면
+
앞의 조건문에서 모든 타입에 대한 분기 처리를 강제 할 수 있다.
+
+> Exhaustiveness Checking을 활용하면 런타임 에러 방지 + 요구사항 변경 시 위험성을 줄일 수 있다.
+
+
+