diff --git "a/CH01_\353\223\244\354\226\264\352\260\200\353\251\260/1.2_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\225\234\352\263\204/seongho.md" "b/CH01_\353\223\244\354\226\264\352\260\200\353\251\260/1.2_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\225\234\352\263\204/seongho.md"
index f64f80d..4f0084e 100644
--- "a/CH01_\353\223\244\354\226\264\352\260\200\353\251\260/1.2_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\225\234\352\263\204/seongho.md"
+++ "b/CH01_\353\223\244\354\226\264\352\260\200\353\251\260/1.2_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\225\234\352\263\204/seongho.md"
@@ -36,7 +36,7 @@ sumNumber('a', 'b'); // 'ab'
ts는 정적타이핑을 제공함으로써 컴파일 단계에서 타입 검사를 해주기 때문에 js를 사용했을 때 빈번하게 발생하는 타입 에러를 줄일 수 있고, 런타임 에러를 사전에 방지할 수 있어서 안정성이 크게 높아짐.
2. **개발 생산성 향상**
-변수와 함수 타입을 추론할 수 있고, 리액트를 사용할떄 어떤 prop을 넘겨야 하는지 매번 확인하지 않아도 바로 볼 수 있어서 개발 생산성이 크기 높아짐.
+변수와 함수 타입을 추론할 수 있고, 리액트를 사용할때 어떤 prop을 넘겨야 하는지 매번 확인하지 않아도 바로 볼 수 있어서 개발 생산성이 크기 높아짐.
3. **협업에 유리**
자동완성 기능이나, 기술된 인터페이스를 활용하여 코드를 쉽게 파악할 수 있음.
diff --git "a/CH02_\355\203\200\354\236\205/2.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seongho.md" "b/CH02_\355\203\200\354\236\205/2.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seongho.md"
index b28cb50..fa19e84 100644
--- "a/CH02_\355\203\200\354\236\205/2.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seongho.md"
+++ "b/CH02_\355\203\200\354\236\205/2.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seongho.md"
@@ -90,7 +90,7 @@ function getPetName(pet: Pet) {
getPetName(dog); // ✅
```
-이게 가능한 이유는 **dog**객체는 **Pet**인터페이스가 갖고있는 **name**이라는 속성을 갖고 있어서 **pet.name**의 방식으로 name에 접근이 가능하기 떄문임.
+이게 가능한 이유는 **dog**객체는 **Pet**인터페이스가 갖고있는 **name**이라는 속성을 갖고 있어서 **pet.name**의 방식으로 name에 접근이 가능하기 때문임.
이런 방식이 바로 `구조적 타이핑`임. 또다른 예시를 보자면
diff --git "a/CH02_\355\203\200\354\236\205/2.4_\352\260\235\354\262\264_\355\203\200\354\236\205/seulgi.md" "b/CH02_\355\203\200\354\236\205/2.4_\352\260\235\354\262\264_\355\203\200\354\236\205/seulgi.md"
index 0dfed1d..bd55ab8 100644
--- "a/CH02_\355\203\200\354\236\205/2.4_\352\260\235\354\262\264_\355\203\200\354\236\205/seulgi.md"
+++ "b/CH02_\355\203\200\354\236\205/2.4_\352\260\235\354\262\264_\355\203\200\354\236\205/seulgi.md"
@@ -53,7 +53,7 @@ console.log(noticePopup.toString()); // [object Object]
타입스크립트 튜플 타입은 배열과 유사하지만 튜플의 대괄호 내부에는 **선언 시점에 지정해준 타입 값만 할당**할 수 있다.
-원소 개수도 타입 선언 시점에 미리 정해진다. 이것은 객체 리터럴에서 선언하지 않은 속성을 할당하거나 선언한 속성을 할당하지 않을 떄 에러가 발생하는 것과 같다.
+원소 개수도 타입 선언 시점에 미리 정해진다. 이것은 객체 리터럴에서 선언하지 않은 속성을 할당하거나 선언한 속성을 할당하지 않을 때 에러가 발생하는 것과 같다.
```ts
const myNames: ["CHU", "SEULGI"] = ["CHU", "SEULGI", "LESLEY"]; // "LESLEY"는 지정할 수 없다.
@@ -105,7 +105,7 @@ console.log(typeof add); // function
호출 시그니처를 정의하는 방식으로 사용하면 된다. 호출 시그니처는 함수의 매개변수와 반환 값의 타입을 명시하는 역할을 한다.
> **호출 시그니처(Call Signature)?**
-> 타입스크립트에서 함수 타입을 정의할 떄 사용하는 문법으로 함수 타입은 해당 함수가 받는 매개변수와 반환하는 값의 타입으로 결정된다.
+> 타입스크립트에서 함수 타입을 정의할 때 사용하는 문법으로 함수 타입은 해당 함수가 받는 매개변수와 반환하는 값의 타입으로 결정된다.
```ts
type add = (a: number, b: number) => number;
diff --git "a/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.3_\354\240\234\353\204\244\353\246\255_\354\202\254\354\232\251\353\262\225/seulgi.md" "b/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.3_\354\240\234\353\204\244\353\246\255_\354\202\254\354\232\251\353\262\225/seulgi.md"
index b28af95..ce49965 100644
--- "a/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.3_\354\240\234\353\204\244\353\246\255_\354\202\254\354\232\251\353\262\225/seulgi.md"
+++ "b/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.3_\354\240\234\353\204\244\353\246\255_\354\202\254\354\232\251\353\262\225/seulgi.md"
@@ -231,7 +231,7 @@ console.log(getNames({})); // Error! Argument of type '{}' is not assignable to
> 위의 코드처럼 제약해버리면 제네릭의 유연성을 잃어버린다.
-### 유연성을 잃어버리지 않고, 제약해야 할 떄는 타입 매개변수 + 유니온 타입 상속 선언을 활용하자
+### 유연성을 잃어버리지 않고, 제약해야 할 때는 타입 매개변수 + 유니온 타입 상속 선언을 활용하자
```ts
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 9ec90af..b29c563 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"
@@ -187,7 +187,7 @@ function handle(param: Unions) {
}
```
-- 해당 코드에서는 판별자가 value일 떄 판별자로 선정한 값 중 "a"만 유일하게 유닛 타입이다.
+- 해당 코드에서는 판별자가 value일 때 판별자로 선정한 값 중 "a"만 유일하게 유닛 타입이다.
- **이때만 유닛 타입을 포함하고 있어 타입이 좁혀진다!**
- 판별자가 answer일 때를 보면 판별자가 모두 유닛 타입이라 타입이 정상적으로 좁혀진다.
diff --git "a/CH05_\355\203\200\354\236\205_\355\231\234\354\232\251\355\225\230\352\270\260/5.1_\354\241\260\352\261\264\353\266\200_\355\203\200\354\236\205/seongho.md" "b/CH05_\355\203\200\354\236\205_\355\231\234\354\232\251\355\225\230\352\270\260/5.1_\354\241\260\352\261\264\353\266\200_\355\203\200\354\236\205/seongho.md"
index 3beced8..5fc5c30 100644
--- "a/CH05_\355\203\200\354\236\205_\355\231\234\354\232\251\355\225\230\352\270\260/5.1_\354\241\260\352\261\264\353\266\200_\355\203\200\354\236\205/seongho.md"
+++ "b/CH05_\355\203\200\354\236\205_\355\231\234\354\232\251\355\225\230\352\270\260/5.1_\354\241\260\352\261\264\353\266\200_\355\203\200\354\236\205/seongho.md"
@@ -1 +1,366 @@
-
+프로그래밍에서는 다양한 상황을 다루기 위해서 조건문을 많이 활용함
+ts에서도 조건에 따라서 타입을 다르게 주어야 할 경우 `조건부 타입`을 사용할 수 있음.
+ts의 조건부 연산자는 js의 `삼항 연산자`와 같은 `condition ? A : B` 구조를 가짐.
+
+
+
+### `extends`와 제네릭을 활용한 조건부 타입
+---
+`extends`는 ts에서 타입을 확장할 때와 타입을 조건부로 설정할 때 사용되며, 제네릭 타입에서는 ***한정자*** 역할로도 사용됨.
+
+**`T extends U ? X : Y`**
+-> 해당 표현은 타입 T를 U에 할당할 수 있다면 X타입, 아니면 Y타입으로 결정됨을 의미함.
+
+예시를 살펴보자
+```ts
+interface Foo {}
+
+interface Bar {}
+
+type One = T extends 'Foo' ? Foo : Bar;
+
+const foo: One<'Foo'> = {}; // Foo 타입
+const bar: One<'Bar'> = {}; // Bar 타입
+```
+해당 예시에서는 제네릭에 `'Foo'`가 들어오면 `Foo타입`을, 아니면 `Bar타입`으로 결정 됨.
+
+
+
+### 조건부 타입을 사용하지 않았을 때의 문제점
+---
+조건부 타입을 사용하기 전에는 어떤 이슈가 있었는지 알아보자.
+아래는 리액트 쿼리를 활용한 예시임.
+(계좌, 카드, 앱카드등 3가지 결제 수단 정보를 가져오는 API가 있으며, API의 엔드포인트는 아래와 같음)
+> [!NOTE]
+> - 계좌 정보 : `www.baemin.com/baeminpay/.../bank`
+> - 카드 정보 : `www.baemin.com/baeminpay/.../card`
+> - 앱카드 정보 : `www.baemin.com/baeminpay/.../appcard`
+
+각 API는 계좌, 카드, 앱카드의 결제 수단 정보를 배열 형태로 반환함. 3가지 API의 엔드포인트가 비슷하기 때문에 서버 응답을 처리하는 공통 함수를 생성하고, 해당 함수에 타입을 전달하여 타입별로 처리 로직을 구현해보자
+
+```ts
+interface PayMethodBaseFromRes {
+ financialCode: string;
+ name: string;
+}
+
+interface Bank extends PayMethodBaseFromRes {
+ fullName: string;
+}
+
+interface Card extends PayMethodBaseFromRes {
+ appCardType: string;
+}
+
+// PayMethodInterface: 프론트에서 관리하는 결제 수단 관련 데이터로 UI를 구현하는데 사용되는 타입.
+type PayMethodInterface = {
+ companyName: string;
+ // ...
+};
+
+type PayMethodInfo = T & PayMethodInterface;
+```
+
+이제 리액트 쿼리의 useQuery를 사용한 커스텀 훅인 `useGetRegisteredList`함수를 살펴보자.
+
+```ts
+type payMethodType = PayMethodInfo | PayMethodInfo;
+
+// useGetRegisteredList는 useQuery의 반환값을 돌려줌.
+export const useGetRegisteredList = (
+ type: 'card' | 'bank' | 'appcard'
+): UseQueryResult => {
+ const url = `baeminpay/codes/${type === 'appcard' ? 'card' : type}`;
+
+ // fetcherFactory는 axios를 래핑해주는 함수이며, 서버에서 데이터를 받아온 후 onSuccess 콜백함수를 거친 결괏값을 반환함.
+ const fetcher = fetchFactory({
+ onSuccess: (res) => {
+ const usablePocketList =
+ res.filter(
+ (payMethod: PayMethodInfo | PayMethodInfo) => payMethod?.useType === 'USE'
+ ) ?? [];
+
+ return usablePayMethodList;
+ }
+ });
+
+ // useCommonQuery는 useQuery를 한번 래핑해서 사용하고 있는 함수로, useQuery의 반환 데이터를 T타입으로 반환함.
+ const result = useCommonQuery(url, undefined, fetcher);
+
+ return result;
+}
+```
+-> `useGetRegisteredList`는 타입을 구분해서 넣는 사용자의 의도와는 다르게 정확한 타입을 반환하지 못하는 함수가 되었음.
+이를 개선하기 위해서는 `extends를 사용한 조건부 타입`을 활용하면 됨.
+
+
+
+### extends 조건부 타입을 활용하여 개선하기
+---
+`useGetRegisteredList`의 반환 데이터는 인자 타입에 따라서 정해져 있음.
+타입으로 `card` 또는 `appcard`를 받는다면 `PayMethodInfo`를 반환하고, `bank`를 받으면, `PayMethodInfo`를 반환 함.
+
+여기서 `PayMethodInfo | PayMethodInfo`였던 `PayMethodType`을 개선해서 다시 작성해보자
+```ts
+type PayMethodInfo
+ = T extends 'app' | 'appcard'
+ ? PayMethodInfo
+ : PayMethodInfo;
+
+export const useGetRegisteredList = (
+ type: T
+): UseQueryResult[]> => {
+ const url = `baeminpay/codes/${type === 'appcard' ? 'card' : type}`;
+
+ // fetcherFactory는 axios를 래핑해주는 함수이며, 서버에서 데이터를 받아온 후 onSuccess 콜백함수를 거친 결괏값을 반환함.
+ const fetcher = fetchFactory({
+ onSuccess: (res) => {
+ const usablePocketList =
+ res.filter(
+ (payMethod: PayMethodInfo) => payMethod?.useType === 'USE'
+ ) ?? [];
+
+ return usablePayMethodList;
+ }
+ });
+
+ // useCommonQuery는 useQuery를 한번 래핑해서 사용하고 있는 함수로, useQuery의 반환 데이터를 T타입으로 반환함.
+ const result = useCommonQuery[]>(url, undefined, fetcher);
+
+ return result;
+}
+```
+-> 이제 조건부 타입을 활용해서 `PayMethodType`이 사용자가 인자에 넣는 타입 값에 맞는 타입만을 반환하도록 구현했음.
+이제 type에 `'card'` 또는 `'appcard'`를 넣으면 `PayMethodInfo`를, `'bank'`를 넣으면 `PayMethodInfo`를 리턴함.
+
+해당 절에서는 타입 확장이 아닌, `extends`의 활용 사례를 살펴보았음. 정리하자면 아래와 같음.
+- `제네릭과 extends를 함께 사용해서 제네릭으로 받는 타입을 제한함. 이는 휴먼에러를 방지할 수 있음.`
+- `extends를 사용해서 조건부 타입을 설정함. 이는 불필요한 타입가드, 타입 단언을 방지할 수 있음.`
+
+
+
+### infer를 활용해서 타입 추론하기
+---
+`extends`를 사용할때는 `infer`키워드를 사용할 수 있음.
+`infer`는 사전적으로 ***'추론하다'*** 라는 의미를 지니고 있는데 이처럼 ts에서도 타입을 추론하는 역할을 함.
+예시를 살펴보자
+
+```ts
+type InnerType> = T extends Array ? K : never;
+const numberList = [1,2,3];
+type Num = InnerType; // number 타입;
+
+type UnpackPromise = T extends Promise[] ? K : any;
+const promiseList = [Promise.resolve('string'), Promise.resolve(123)];
+type Expected = UnpackPromise; // string | number 타입
+```
+
+이처럼 `extends`와 `infer`, `제네릭`을 활용하면 타입을 조건에 따라 더 세밀하게 사용할 수 있음.
+이번에는 배민에서 사용하는 예시를 살펴보자
+
+```ts
+interface RouteBase {
+ name: string;
+ path: string;
+ component: ComponentType;
+}
+
+export interface RouteItem {
+ name: string;
+ path: string;
+ component?: ComponentType;
+ pages?: routeBase[];
+}
+
+export const routes: RouteItem[] = [
+ {
+ name: '기기내역 관리',
+ path: '/device-history',
+ component: DeviceHistoryPage,
+ },
+ {
+ name: '헬멧 인증 관리',
+ path: '/helmet-certification',
+ component: HelmetCertificationPage,
+ },
+ //...
+]
+```
+RouteBase와 RouteItem은 라이더 어드민에서 라우팅을 위해 사용하는 타입임. routes같이 배열 형태로 사용되며, 권한 API로 반환된 사용자 권한과, name을 비교해서, 인가되지 않은 사용자의 접근을 방지함.
+_`RouteItem`의 name은 pages가 있을때는 단순 이름의 역할만 하지만, 그렇지 않을 경우에는 사용자 권한과 비교함._
+
+> [!NOTE]
+> **라우팅**
+> 웹 애플리케이션에서 사용자가 URL을 통해 다른 페이지로 이동하거나, 다른 경로에 대한 요청을 처리하는 방법을 정의해놓은 것.
+
+
+
+```ts
+interface SubMenu {
+ name: string;
+ path: string;
+}
+
+interface MainMenu {
+ name: string;
+ path?: string;
+ subMenus?: SubMenu[];
+}
+
+type MenuItem = MainMenu | SubMenu;
+const menuList: MenuItem[] = [
+ {
+ name: '계정 관리',
+ subMenus: [
+ {
+ name: '기기 내역 관리',
+ path: '/devide-history'
+ },
+ {
+ name: '헬멧 인증 관리',
+ path: '/helmet-certification',
+ }
+ ],
+ },
+ {
+ name: '운행 관리',
+ path: '/operation',
+ // ...
+ }
+];
+```
+
+MainMenu와 SubMenu은 메뉴 리스트에서 사용하는 타입으로, 권한 API로 반환된 사용자 권한과, name을 비교해서 사용자가 접근할 수 있는 메뉴만 렌더링 함.
+_`MainMenu`의 name은 `SubMenus`가 있을때는 단순 이름의 역할만 하지만, 그렇지 않을 경우에는 사용자 권한과 비교함.(권한으로 간주 됨)_
+
+menuList에는 `MainMenu`와 `SubMenu`타입이 올 수 있기 때문에 유니언 타입인 MenuItem을 정의해서 사용중임.
+따라서 menuList에서 subMenus가 없는 MainMenu의 name과 subMenus에서 쓰이는 name, route name에 **동일한 문자열만 입력해야 한다**는 제약이 존재함.
+
+즉, 권한 문자열이 모두 동일하게 들어 있어야 한다는 것임.
+예를 들어, 이런 구조가 있다고 치자
+```ts
+routes = [
+ { name: '기기내역 관리', path: '/device-history' }
+];
+
+menuList = [
+ {
+ name: '계정 관리',
+ subMenus: [
+ { name: '기기 내역 관리', path: '/device-history' } // 띄어쓰기 다름
+ ]
+ }
+];
+
+userPermissions = ['기기 내역 관리']; // 권한 API로부터 받은 권한 이름
+```
+이 경우 `routes[].name`은 `"기기내역 관리"`, `subMenus[].name`은 `"기기 내역 관리"`
+→ 문자열이 다르기 때문에 비교에 실패할 수 있음
+
+***즉, 권한 이름과 비교되는 대상이 3군데에 흩어져 있어서 이름이 완전히 일치해야만 인가 판단이 정확해짐.***
+
+하지만, 모두 string타입이기 때문에 다른 문자열이 들어가도 컴파일 타임에서 에러가 발생하지 않음.
+이를 개선하기 위해서 `PermissionType`같은 타입을 별도로 선언해서 관리하는 방법도 있지만, 권한 검사가 필요없는 subMenus나 pages가 존재하는 name은 별도로 처리해주어야 함.
+```ts
+type PermissionType = '기기 내역 관리' | '헬멧 인증 관리' | '운행 여부 조회'; //...
+```
+
+이때 `infer`와 `불변 객체`를 활용해서 menuList또는 routes의 값을 추출하여 타입으로 정의하는 식으로 개선할 수 있음.
+```ts
+type UnpackMenuNames>
+ = T extends ReadOnlyArray
+ ? U extends MainMenu
+ ? U['subMenus'] extends infer V
+ ? V extends ReadOnlyArray
+ ? UnpackMenuNames
+ : U['name']
+ : never
+ : U extends SubMenu
+ ? U['name']
+ : never
+ : never;
+```
+-> 타입 추론을 계속 하면서 권한 네이밍을 찾는 커스텀 유틸리티 타입임.
+
+- U가 MainItem이라면 subMeus를 V로 추출함
+- subMenus는 옵셔널이기 때문에 V가 존재한다면 UnpackMenuNames에 다시 전달함(재귀)
+- 없다면 MainMenu의 names은 권한이므로 `U['name']`을 return.
+- U가 MainMenu가 아니라면(SubMenu) `U['name']`은 권한에 해당함.
+
+따라서 아래와 같이 개선이 가능함
+```ts
+interface ComponentType {}
+
+type ReadOnlyArray = Array<{
+ readonly [K in keyof T]: T[K];
+}>;
+
+interface SubMenu {
+ name: string;
+ path: string;
+}
+
+interface MainMenu {
+ name: string;
+ path?: string;
+ subMenus?: ReadOnlyArray;
+}
+
+type MenuItem = MainMenu | SubMenu;
+
+const menuList: ReadOnlyArray