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/seongho.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/seongho.md"
index 3beced8..f7a0c5c 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/seongho.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/seongho.md"
@@ -1 +1,235 @@
-
+### 타입 가드에 따라 분기 처리하기
+---
+ts에서 타입 `좁히기(타입 가드)`는 변수 또는 표현식의 타입 범위를 더 작은 범위로 좁혀나가는 과정임.
+
+이로 인해서 타입의 안정성을 높일 수 있음.
+
+ts로 개발을 하다보면 여러 타입을 할당할 수 있는 `스코프`에서 특정 타입을 조건으로 만들어서 분기 처리하고 싶을 경우가 있음.
+
+> [!TIP]
+> **스코프(Scope)**
+> 변수가 함수등의 식별자가 유효한 범위를 나타냄.
+> 즉, 변수와 함수를 선언하거나 사용할 수 있는 영역을 말함.
+
+예를 들어서 어떤 함수가 `A | B`타입의 매개변수를 받고, 이를 구분해서 처리하고 싶다면 어떻게 해야 할까?
+`if문`을 사용해서 처리하면 될 것 같지만 `ts`는 컴파일 시 타입 정보가 모두 제거되기 때문에 타입을 사용해서 조건을 만들 수는 없음. 즉, 컴파일을 해도 사라지지 않는 방법을 사용해야 함.
+
+***그렇게 하려면 ts가 해당 변수를 타입 A로 추론되게끔 하면서, 런타임에서도 유효한 방법이 필요한데, 이때 `타입 가드`를 사용하면 됨.***
+
+타입 가드는 크게 두가지로 분류할 수 있음.
+- 타입 가드
+ - `js 연산자를 활용한 타입 가드`
+ - `사용자 정의 타입 가드`
+
+`js연산자를 활용한 타입 가드`
+: `typeof`, `instanceof`, `in`과 같은 연산자를 사용해서 특정 타입 값을 가질 수밖에 없는 상황을 유도하여 자연스럽게 타입을 좁히는 방식.
+
+
+
+`사용자 정의 타입 가드`
+: 사용자가 직접 어떤 타입으로 좁힐지 지정하는 방식.
+
+
+
+### 원시타입을 추론할 때: `typeof` 연산자 활용하기
+---
+`typeof`연산자를 활용하면 원시 타입에 대해 추론이 가능함. 다만, typeof는 js타입 시스템만 대응이 가능함.
+또한 `null`과 `배열`등의 타입이 `object`로 판별되는 등, 복잡한 타입을 검증하기에는 한계가 있음.
+***따라서 `typeof`는 주로 하위에 명시된 원시 타입을 좁히는 용도로만 사용할 것을 권장.***
+- `string`
+- `number`
+- `boolean`
+- `undefined`
+- `object`
+- `function`
+- `bigint`
+- `symbol`
+
+```ts
+const Foo:(date: string | Date): string | Date = (date) => {
+ if (typeof date === 'string') {
+ date.toUpperCase(); // 여기서 date는 string타입으로 추론.
+ }
+
+ return date;
+};
+```
+
+
+
+### 인스턴스화 된 객체 타입을 판별할 경우: `instanceof` 연산자 활용하기
+---
+```ts
+interface DateRange {
+ start: Date;
+ end: Date;
+}
+
+interface Params {
+ selectedDate?: Date | DateRange;
+}
+
+const DatePicker = ({selectedDate}: Params) {
+ const [selected, setSelected] = useState(convertToRange(selectedDate));
+};
+
+const convertToRange: (selected: DateRange | Date) => DateRange = (selected) => {
+ if (selected instanceof Date) {
+ return { start: selected, end: selected };
+ }
+
+ return selected;
+};
+```
+`typeof` 연산자를 주로 원시타입을 판별하는데, 사용한다면 `instanceof` 연산자는 인스턴스 화 된 객체 타입을 판별하는 타입 가드로 사용할 수 있음.
+다만 주의해야 할 점은 프로토타입 속성의 변화에 따라서 instanceof 연산자의 결과가 달라질 수 있다는 점임.
+> [!NOTE]
+> **instanceof**
+> `object instanceof constructor` 형태로 작성하고
+> object의 프로토타입 체인에 constructor.prototype이 존재하는지 판별함
+
+
+
+### 객체의 속성이 있는지 없는지에 따른 구분: `in` 연산자 활용하기
+`in`연산자는 객체에 속성이 있는지 확인한 다음에 `true` 또는 `false`를 반환함.
+
+만약, 내가 `Foo` 또는 `Bar`타입을 인자로 받고, 각각의 타입에 따라서 popup을 다르게 띄워주고 싶다고 해보자.
+그러면 아래와 같이 `in`을 활용해서 작성할 수 있음.
+
+```ts
+interface Foo {
+ name: string;
+ age: number;
+}
+
+interface Bar extends Foo {
+ hasJob: boolean;
+}
+
+const showPopup = (contents: Foo | Bar) => {
+ if ('hasJob' in contents) {
+ return openBarPopup(contents);
+ // hasJob은 Bar타입에만 존재하기 때문에 여기서는 contents가 Bar타입으로 추론 됨.
+ }
+
+ // 위에서 early return을 했기 때문에, 해당 구문에서는 contents가 Foo타입으로 추론 됨.
+ return openFooPopup(contents);
+}
+```
+***js에서 in은 런타임의 값만을 검사하지만, ts에서 in은 객체 타입에 속성이 존재하는지 검사함.***
+
+이처럼 여러 객체 타입을 유니온 타입으로 갖고있을 경우, `in` 연산자를 활용해서 타입 가드를 할 수 있음.
+
+
+
+### is 연산자로 사용자 정의 타입 가드 만들어 활용하기
+---
+직접 `타입 가드 함수`를 만들어서 사용할 수도 있음. 이러한 방식은 반환 타입이 `타입 명제`인 함수를 정의해야 함.
+
+> [!TIP]
+> **타입 명제**란?
+> `A is B` 방식으로 작성하는데, 여기서 `A`는 매개변수 이름이고, `B`는 타입임.
+> 해당 함수는 `boolean` 타입을 반환해야 하는데, `true`를 return 할 때 **A의 타입을 B로 취급**함.
+> ```ts
+> interface Foo {
+> name: string;
+> age: number;
+>}
+>
+>interface Bar extends Foo {
+> hasJob: boolean;
+>}
+>
+>const isBar = (params: Foo | Bar): params is Bar => {
+> return 'hasJob' in params;
+>}
+>
+>const showPopup = (contents: Foo | Bar) => {
+> if (isBar(contents)) {
+> return openBarPopup(contents); // isBar타입가드에 의해서 contents가 Bar타입으로 추론 됨.
+> }
+>
+> // 위에서 early return을 했기 때문에, 해당 구문에서는 contents가 Foo타입으로 추론 됨.
+> return openFooPopup(contents);
+>}
+> ```
+
+노티 박스보다 조금 더 심화된 예시를 봐보자
+```ts
+const isDestinationCode(x: string): x is DestinationCode => {
+ return destinationCodeList.includes(x);
+}
+
+const getAvailableDestinationNameList = async (): Priomise => {
+ const data = await AxiosRequest('get', '.../destinations');
+ const destinationNames = DestinationName[] = [];
+
+ data?.forEach((str) => {
+ if (isDestinationCode(str)) {
+
+ destinationNames.push(DestinationNameSet[str]);
+ }
+ });
+
+ return destinationNames;
+}
+```
+해당 코드는 if문 내 `isDestination`함수로 `data`의 str이 `destinationCodeList`의 문자열 원소인지 체크하고, 맞다면 `destinationNames`배열에 push를 하는 코드임.
+만약, `isDestinationCode`의 return 타입인 `x is DestinationCode`를 boolean으로 작성했으면 어땠을까?
+
+개발자라면 `destinationCodeList.includes(x);`를 해석할 수 있기 때문에 이해할 수 있지만, ts는 str의 타입을 좁히지 못함.
+이처럼 ts에게 반환값에 대한 타입 정보를 알려주고 싶을 경우 `is`를 사용할 수 있음.
+
+
+
+### 나의 실무 예시
+---
+끝으로, 내가 실무에서 실제로 작성한 `커스텀 타입 가드`를 예시로 봐보자
+
+`Promise.allSettled`는 여러개의 promise를 배열로 받아서 비동기적으로 실행해주는 메서드임.
+Promise.all도 동일하게 여러개의 promise를 담은 배열을 인자로 받아서 비동기적으로 실행시켜 주지만
+`Promise.all`은 여러개의 promise중 하나의 promise라도 성공적으로 완료되지 못하면 동시에 실행된 모든 promise가 reject되는 반면,
+`Promise.allSettled`는 동시에 실행된 promise들 중에서 성공적으로 완료되지 못한 promise가 발생해도 전부 reject되지 않고, 성공적으로 완료된 promise들을 확인할 수 있음.
+
+그렇기에 `Promise.allSetted`가 return하는 타입인 `Promise>`를 살펴보면
+수행한 **promise가 성공적으로 마무리 됬을경우** 할당되는 `PromiseFulfilledResult`와,
+**promise가 성공적으로 마무리 되지 못했을 경우** 할당되는 `PromiseRejectedResult`를 `유니언 타입`으로 return하고 있는 것을 볼 수 있음.
+
+
+
+
+
+그렇기에 나는 아래와 같은 `커스텀 타입 가드`를 작성해서 유틸 함수로 사용하고 있음.
+```ts
+const isFulfilled = (
+ targetResult: PromiseSettleResult
+): targetResult is PromiseFulfilledResult =>
+ targetResult.status === 'fulfilled';
+```
+해당 `커스텀 타입 가드`는 `PromiseSettledResult`의 타입을 가진 `targetResult`라는 파라미터를 받아서
+만약, 해당 파라미터의 status가 `fulfilled`라면
+targetResult의 타입을 `PromiseFulfilledResult`로 취급하도록 하는 `커스텀 타입 가드`
+
+
+해당 타입가드를 어떻게 활용하고 있을까?
+
+
+`Promise.allSettled`를 통해 여러개의 API를 묶어서 병렬적으로 처리한 뒤,
+각각의 응답을 `isFulfilled 커스텀 타입 가드`를 통해 status가 fulfilled인지 체크하여, 만약 status가 fulfilled라면 성공한 프로미스 타입으로 취급시켜 주는 것.
+
+```ts
+const [
+ dataCategoryResult, // 여기서 dataCategoryResult는 PormiseSettledResult가 됨
+ // ...
+] = Promise.allSettled([
+ getCagetory(params.categoryId),
+ // ...
+])
+
+const dataCategory = isFulfilled(dataCategoryResult)
+ ? dataCategoryResult.value // 여기서 dataCategoryResult는 타입 가드를 통해서 PormiseFulfilledResult가 됨
+ : undefined;
+```
+
+
+이렇게 활용하고 있음.
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/seongho.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/seongho.md"
index 3beced8..183321c 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/seongho.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/seongho.md"
@@ -1 +1,162 @@
-
+종종 `태그된 유니온`으로도 불리는 `식별할 수 있는 유니온`은 타입 가드에 널리 사용되는 방식임.
+예시와 함께 살펴보자
+
+
+
+### 에러 정의하기
+---
+배민 서비스에서는 선물을 보낼때 사용자가 필요한 값을 올바르게 입력했는지를 확인하는 유효성 검사를 진행함.
+이때 다양한 방식으로 에러를 보여주는데, 크게 3가지로 분류함.
+- `텍스트 에러`
+- `토스트 에러`
+- `얼럿 에러`
+
+이들을 모두 동일하게, `errorCode`와 `errorMessage`를 가지고 있지만, 각각 추가로 필요한 정보가 있을 수 있음. 예를 들자면 토스트 에러는 토스트를 얼마나 오래 띄울것인지에 대한 정보가 필요함.
+```ts
+type TextError = {
+ errorCode: string;
+ errorMessage: string;
+};
+
+type ToastError = {
+ errorCode: string;
+ errorMessage: string;
+ toastShowDuration: number; // 토스트 유지 시간
+};
+
+type AlertError = {
+ errorCode: string;
+ errorMessage: string;
+ onConfirm: () => void; // 확인 버튼을 누른 뒤 action
+};
+```
+
+이 에러 타입의 유니온 타입을 원소로 하는 배열을 정의하면 아래와 같음
+```ts
+type ErrorFeedbackType = TextError | ToastError | AlertError;
+
+const errorArr: ErrorFeedbackType[] = [
+ { errorCode: '100', errorMessage: '텍스트 에러' },
+ { errorCode: '200', errorMessage: '토스트 에러', toastShowDuration: 300, },
+ { errorCode: '300', errorMessage: '얼럿 에러', onConfirm: () => {}, },
+];
+```
+
+
+
+여기서 만약 `TextError`, `ToastError`, `AlertError`의 모든 속성을 가지는 에러가 들어온다고 가정해보면
+```ts
+const unionError = {
+ errorCode: '999',
+ errorMessage: '잘못된 에러',
+ toastShowDuration: 300,
+ onConfirm: () => {},
+};
+
+errorArr.push(unionError); // ✅ OK
+```
+이거는 우리가 기대했던 상황이 아니므로 에러를 뱉어야 하는게 맞지만, 덕타이핑 언어의 특성을 가지는 js이기 때문에 별도의 타입 에러가 발생하지 않음.
+따라서 이러한 상황에서 에러가 발생하지 않으면 앞으로의 개발 과정에서 알수없는 에러가 많이많이 생기게 될게 뻔함.
+
+
+
+### 식별할 수 있는 유니온
+---
+따라서 에러 타입을 구분할 방법이 필요한데, 각 타입이 비슷한 구조를 가지지만 서로 호환되지 않도록 하기 위해서는 타입들이 서로 포함 관계를 가지지 않도록 정의해야 함.
+***즉, 차별점이 될만한 것들을 정의해두어야 한다는 것.***
+이때 적용할 수 있는 방법이 바로 `식별할 수 있는 유니온`을 활용하는 것임.
+`식별할 수 있는 유니온`이란 ***타입간의 구조 호환을 막기 위해 타입마다 구분할 수 있는 유니크한 식별자(판별자)를 달아줘서 포함 관계를 제거하는 것*** 임.
+
+위에서 보았던 예시를 식별자의 개념으로 `errorType`이라는 필드를 추가해서 다시 작성 해본다면
+```ts
+type TextError = {
+ errorType: 'TEXT'; // 식별자
+ errorCode: string;
+ errorMessage: string;
+};
+
+type ToastError = {
+ errorType: 'TOAST'; // 식별자
+ errorCode: string;
+ errorMessage: string;
+ toastShowDuration: number;
+};
+
+type AlertError = {
+ errorType: 'ALERT'; // 식별자
+ errorCode: string;
+ errorMessage: string;
+ onConfirm: () => void;
+};
+```
+이렇게 작성해 볼 수 있음.
+`errorType`으로 각각 고유한 식별자를 넣어줌으로써 포함관계를 제거했음.
+그렇다면 아까는 에러를 뱉지 않았던 예시를 다시 적용해본다면?
+
+
+우리가 기대했던 대로 동작함.
+유니크한 식별자를 통해서 ts가 타입 추론을 통해서 타입을 좁힌 것.
+
+
+
+### 식별할 수 있는 유니온 판별자 선정
+---
+식별할 수 있는 유니온을 사용할 때 주의할 점이 있음.
+식별할 수 있는 유니온의 판별자(식별자)는 `유닛 타입`으로 선언되어야 한다는 것.
+> [!TIP]
+> **유닛 타입**
+> 다른 타입으로 쪼개지지 않고 오직 하나의 정확한 값을 가지는 타입을 말함.
+> ex) `null`, `undefined`, `true`, `1`, `리터럴 타입` 등등..
+
+여러 타입 할당이 가능한 `void`, `string`, `number`, `object`이런 타입들은 유닛 타입으로 분류되지 않음.
+
+실제 ts 깃헙의 이슈를 찾아보면 식별자로 사용 가능한 타입을 다음과 같이 정의하고 있음
+- ***"리터럴 타입이어야 한다."***
+- ***판별자(식별자)로 선정한 값에 적어도 하나 이상의 유닛 타입이 포함되어야 하며, 인스턴스화할 수 있는 타입은 포함되지 않아야 한다.***
+
+```ts
+interface A {
+ value: 'a';
+ answer: 1;
+}
+
+interface B {
+ value: string;
+ answer: 2;
+}
+
+interface C {
+ value: Error;
+ answer: 3;
+}
+
+function checkType(param: A | B | C) {
+ // 식별자가 param.value일 경우
+ if (param.value === 'a') {
+ param // A | B 타입으로 좁혀짐
+ }
+
+ if (typeof param.value === 'string') {
+ param // A | B 타입으로 좁혀짐
+ }
+
+ if (param.value instanceof Error) {
+ // 인스턴스화 할 수 있는 타입일 경우 타입이 좁혀지지 않음.
+ param // A | B | C
+ }
+
+ // 식별자가 param.answer일 경우
+ if (param.answer === 1) {
+ param // A
+ }
+
+ if (param.answer === 2) {
+ param // B
+ }
+
+ if (param.answer === 3) {
+ param // C
+ }
+}
+```
+이 코드에서는 판별자가 `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/seongho.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/seongho.md"
index 3beced8..c130791 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/seongho.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/seongho.md"
@@ -1 +1,70 @@
-
+`Exhaustiveness`는 사전적으로 철저함, 완전함을 의미함.
+따라서 `Exhaustiveness Checking`은 모든 케이스에 대해 철저하게 타입을 검사하는 것을 말함.
+타입 가드를 통해서 타입에 대한 분기 처리를 수행한다면 분기 처리가 필요하다고 생각되는 부분에만 분기처리를 해준다면 요구사항을 만족할 수 있음. 그러나 때로는 모든 케이스에 대해서 분기처리를 해야만 하는 상황이 있을 수 있음.
+
+예를 들어서 살펴보자
+
+
+
+### 상품권
+---
+배민 서비스에는 다양한 상품권들이 존재함. 상품권의 가격에 따라 상품권의 이름을 반환해주는 함수를 작성하면 다음과 같음.
+```ts
+type ProductPrice = 10000 | 20000;
+
+const getProductName = (productPrice: ProductPrice) => {
+ if (productPrice === 10000) {
+ return '배민상품권 1만원';
+ }
+
+ if (productPrice === 20000) {
+ return '배민상품권 2만원';
+ }
+
+ else {
+ return '배민상품권';
+ }
+};
+```
+해당 코드는 가격에 따라서 이름을 잘 반환하고 있지만, 만약 `ProductPrice`에 `5000`이 새로 추가된다면?
+`getProductName`의 코드에도 새로운 분기처리 코드가 추가가 되어야 할것임.
+수정을 하지 않아도 에러가 발생 하는것은 아니기 때문에 실수 할 여지도 있음.
+
+
+
+이러한 실수를 방지하기 위해서 모든 타입에 대해서 타입 검사를 강제하고 싶다면 아래와 같이 코드를 작성할 수 있음.
+
+```ts
+type ProductPrice = 5000 | 10000 | 20000;
+
+const getProductName = (productPrice: ProductPrice) => {
+ if (productPrice === 10000) {
+ return '배민상품권 1만원';
+ }
+
+ if (productPrice === 20000) {
+ return '배민상품권 2만원';
+ }
+
+ else {
+ exhaustiveTypeCheck(productPrice);
+ }
+};
+
+const exhaustiveTypeCheck = (param: never): never => {
+ throw new Error('처리되지 않은 타입이 존재합니다!!');
+}
+```
+
+
+
+-> 이미지를 보면 타입 분기 처리를 빼먹었을 경우 의도적으로 에러를 발생시킴.
+
+`exhaustiveTypeCheck`의 인자 타입을 `never`로 선언해서 어떤 값도 받지 못하게 한 뒤, 만약 특정 값이 들어오면 에러를 뱉게끔 하는 것임.
+
+
+이런식으로 모든 타입에 대해서 분기 처리를 하지 않았을 경우 의도적으로 에러를 던져서 컴파일 에러를 유도하는 방식을 `Exhaustiveness Checking`이라고 함.
+
+
+
+
diff --git a/README.md b/README.md
index a0c219f..f924f06 100644
--- a/README.md
+++ b/README.md
@@ -30,8 +30,8 @@
| ------ | --------------------------------------------------------------------------------------- | ---------- | --------- |
| 1주차 | 1.1 웹 개발의 역사 ~ 2.4 객체 타입 | 2025.03.11 | ✅ |
| 2주차 | 3.1 타입스크립트만의 독자적 타입 시스템 ~ 3.2 타입 조합 | 2025.03.18 | ✅ |
-| 3주차 | 3.3 제네릭 사용법 ~ 4.1 타입 확장하기 | YYYY.MM.DD | |
-| 4주차 | 4.2 타입 좁히기 - 타입 가드 ~ 4.4 Exhaustiveness Checking으로 정확한 타입 분기 유지하기 | YYYY.MM.DD | |
+| 3주차 | 3.3 제네릭 사용법 ~ 4.1 타입 확장하기 | 2025.03.25 | ✅ |
+| 4주차 | 4.2 타입 좁히기 - 타입 가드 ~ 4.4 Exhaustiveness Checking으로 정확한 타입 분기 유지하기 | 2025.04.01 | ✅ |
| 5주차 | 5장 타입 활용하기 | YYYY.MM.DD | |
| 6주차 | 6.1 자바스크립트의 런타임과 타입스크립트의 컴파일 ~ 7.1 API 요청 | YYYY.MM.DD | |
| 7주차 | 7.2 API 상태 관리하기 ~ 7.4 API 모킹 | YYYY.MM.DD | |
diff --git a/assets/CH04/discriminant_union_example.png b/assets/CH04/discriminant_union_example.png
new file mode 100644
index 0000000..156523d
Binary files /dev/null and b/assets/CH04/discriminant_union_example.png differ
diff --git a/assets/CH04/exhaustiveness_type_check.png b/assets/CH04/exhaustiveness_type_check.png
new file mode 100644
index 0000000..56865ac
Binary files /dev/null and b/assets/CH04/exhaustiveness_type_check.png differ
diff --git a/assets/CH04/fulfilled_promise_image.png b/assets/CH04/fulfilled_promise_image.png
new file mode 100644
index 0000000..e9bb8f4
Binary files /dev/null and b/assets/CH04/fulfilled_promise_image.png differ
diff --git a/assets/CH04/promiseSettledResult.png b/assets/CH04/promiseSettledResult.png
new file mode 100644
index 0000000..b921363
Binary files /dev/null and b/assets/CH04/promiseSettledResult.png differ
diff --git a/assets/CH04/promise_allSettled.png b/assets/CH04/promise_allSettled.png
new file mode 100644
index 0000000..4dcaeec
Binary files /dev/null and b/assets/CH04/promise_allSettled.png differ