diff --git "a/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.1_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\353\247\214\354\235\230_\353\217\205\354\236\220\354\240\201_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seulgi.md" "b/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.1_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\353\247\214\354\235\230_\353\217\205\354\236\220\354\240\201_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seulgi.md"
index 3beced8..ee69d14 100644
--- "a/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.1_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\353\247\214\354\235\230_\353\217\205\354\236\220\354\240\201_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seulgi.md"
+++ "b/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.1_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\353\247\214\354\235\230_\353\217\205\354\236\220\354\240\201_\355\203\200\354\236\205_\354\213\234\354\212\244\355\205\234/seulgi.md"
@@ -1 +1,424 @@
-
+# 타입스크립트만의 독자적 타입 시스템
+
+타입스크립트는 자바스크립트의 자료형에서 제시하지 않은 독자적인 타입 시스템을 가지고 있다.
+
+자바스크립트의 슈퍼셋으로 정적 타이핑을 할 수 있는 타입스크립트가 등장하면서 비로소 타입스크립트의 타입 시스템이 구축되었다.
모든 타입 시스템은 타입스크립트에만 존재하는 키워드지만,
그 개념은 자바스크립트에 기인한 타입 시스템이라는 걸 인지하고 타입을 살펴봐야 한다.
+
+
+
+
+
+
+## 1) any 타입
+
+any 타입은 모든 값을 오류 없이 받을 수 있다. 자바스크립트에서의 기본 사용 방식과 같으므로 타입을 명시하지 않은 것과 동일한 효과를 나타낸다.
+
+타입스크립트는 동적 타이핑 특징을 가진 자바스크립트에 정적 타이핑을 적용하는 것이 주된 목적이지만 any타입은 이러한 목적을 무시할 수 있다.
+
+### tsconfig.json 파일에서 any에 대한 경고를 설정할 수 있다!
+
+tsconfig.json 파일에서 **noImplicitAny** 옵션을 활성화하면 타입이 명시되지 않은 변수의 암묵적인 any 타입에 대한 경고를 발생시킬 수 있다.
+
+### any 타입을 어쩔 수 없이 사용해야 할 때를 알아보자!
+
+**(1) 개발 단계에서 임시로 값을 지정해야 할 때**
+
+추후 값이 변경될 가능성이 있거나 아직 세부 항목에 대한 타입이 확정되지 않은 경우, any로 지정해 타입을 세세하게 명시하는 데 소요되는 시간을 절약할 수 있다.
+
+**(2) 어떤 값을 받아올지 또는 넘겨줄지 정할 수 없을 때**
+
+API 요청 및 응답 처리, 콜백 함수 전달, 타입이 잘 정제되지 않아 파악이 힘든 외부 라이브러리 등을 사용할 때 어떤 인자를 주고받을지 특정하기 힘들 때가 있다.
+
+이처럼 주고받을 값이 명확하지 않을 때 any타입을 선언해야 할 수 있다.
+
+```ts
+type ModalParams = {
+ show: boolean;
+ // ...
+ action?: any;
+};
+```
+
+- action 속성은 모달 창을 그릴 때 실행될 함수이다.
+- 다양한 범주의 액션에 따라 인자의 개수나 타입을 일일이 명시하기 힘들 수 있다.
+
+> 이때 any 타입을 사용해 다양한 액션 함수를 전달할 수 있다.
+
+**(3) 값을 예측할 수 없을 때 암묵적으로 사용**
+
+브라우저의 `Fetch API`처럼 다양한 값을 반환하는 API가 있다.
+
+`Fetch API` 일부 메서드는 요청 이후 응답을 특정 포맷으로 파싱하는데 이때 반환 타입이 any로 매핑되어 있다.
+
+```ts
+async function load() {
+ const response = await fetch("https://api.com");
+ const result = await response.json();
+
+ return result;
+}
+```
+
+> response.json()의 리턴 타입은 Promise로 정의되어 있다.
+
+**그럼에도 되도록이면 any타입은 지양하는 것이 좋다. 타입 검사를 무색하게 만들고 잠재적으로 위험한 상황을 초래할 수 있다.**
+
+
+
+
+## 2) unknown 타입
+
+unknown 타입은 모든 타입의 값이 할당될 수 있는 타입으로 타입스크립트 3.0이 릴리즈 될 때 추가되었다.
+
+### any와의 차이점을 알아보자!
+
+| 비교사항 | any | unknown |
+| ----------------------------------- | --- | ---------------------- |
+| 어떤 타입이든 해당 타입에 할당 가능 | O | O |
+| 해당 타입을 다른 타입으로 할당 가능 | O | X (any 타입 외 불가능) |
+
+```ts
+let unknownValue: unknown;
+
+unknownValue = "100"; // ✅ 함수, 숫자, 문자열 다 할당 가능
+unknownValue = 100; // ✅
+
+let a: any = unknownValue; // ✅ any 타입으로 선언한 변수를 제외한 다른 변수 모두 할당 불가
+let b: string = unknownValue; // ❌
+```
+
+### any타입과 비슷한데 왜 unknown 타입이 추가되었을까?
+
+```ts
+const aFunction: unknown = () => console.log("a");
+aFunction(); // ❌ 'aFunction' is of type 'unknown'.
+```
+
+위의 예시처럼 함수를 unknown타입 변수에 할당할 때는 컴파일러가 경고를 주지 않는다.
+실행하면 에러가 발생하는데 함수뿐만 아니라 객체 속성 접근,
+클래스 생성자 호출을 통한 인스턴스 생성 등 객체 내부에 접근하는 모든 시도에서 에러가 발생한다.
+
+### 왜 호출 시 문제가 생길까?
+
+unknown 타입으로 할당된 변수는 어떤 값이든 올 수 있음을 의미하는 동시에 개발자에게 엄격한 타입 검사를 강제하는 의도를 담고 있다. any 타입으로 사용할 경우 런타임에 예상치 못한 버그가 발생할 가능성이 높아지는데 unknown 타입은 이런 상황을 보완한다.
+
+### any보다 어떤 점이 더 좋을까?
+
+- any타입과 유사하지만 타입 검사를 강제한다.
+- 타입이 식별된 후에 사용할 수 있어 더 안전하다.
+- 데이터 구조를 파악하기 힘들 때는 unknown 타입으로 대체해서 사용하는 방법이 권장된다.
+
+> 다만 어떤 값을 받을 지 모르는 상황에서 unknown을 사용하면 가공할 때 타입 캐스팅을 모두 해야 하는 상황이 생길 수 있다. (자바스크립트에서 타입스크립트로 변환 시도 동일)
+
+### 또, 어떨 때 unknown 타입을 활용할 수 있을까?
+
+```ts
+const env = process.env as unknown as ProcessEnv;
+```
+
+위처럼 강제 타입 캐스팅을 통해 타입을 전환할 때 사용한다.
+
+혹은, 타입스크립트 4.4부터 try-catch 에러의 타입이 any에서 unknown으로 변경되서 에러 핸들링을 할 때도 unknown을 사용할 수 있다.
+
+다만 `as unknown as Type` 같이 강제 타입 캐스팅을 하기도 하는데 any와 다를게 없어 지양해야 한다.
+
+
+
+
+## 3) void 타입
+
+함수에 전달되는 매개변수의 타입과 반환하는 타입을 지정해야 하는데 타입스크립트에서는 함수가 어떤 값을 반환하지 않는 경우는 void로 지정하여 사용한다.
+
+- void 타입은 undefined가 아니다.
+- 함수에 국한된 타입은 아니다.
+- 변수에도 할당할 수 있지만 함수가 아닌 값에 대해선 대부분 무의미하다.
+- void로 할당된 변수는 undefined 또는 null값만 할당할 수 있다.
+- 명시적인 의미를 부여하는 관점에서 undefined와 null 타입 키워드를 직접 사용해 타입을 지정하는 것이 더 바람직하다.
+- 일반적으로 함수 자체를 다른 함수 인자로 전달하는 경우가 아니면 void 타입은 잘 명시하지 않는다.(알아서 컴파일러가 추론하기 때문)
+
+
+
+
+## 4) never 타입
+
+일반적으로 함수 관련해서 많이 사용되는 타입으로, 값을 반환할 수 없는 타입을 말한다. 여기서 값을 반환하지 않는 것과 반환할 수 없는 것을 명확히 구분해야 한다.
+
+### 자바스크립트에서 값을 반환할 수 없는 예시를 알아보자!
+
+**(1) 에러를 던지는 경우**
+
+자바스크립트는 런타임에 의도적으로 에러를 발생시키고 캐치할 수 있다.
+
+throw 키워드를 사용해 에러를 발생시킬 때, 이는 값을 반환하는 것으로 간주하지 않는다. 특정 함수가 실행 중 마지막에 에러를 던지는 작업을 수행한다면 해당 함수의 반환 타입은 never이다.
+
+```ts
+function generateError(res: Response): never {
+ throw new Error(res.getMessage());
+}
+```
+
+**(2) 무한히 함수가 실행되는 경우**
+
+함수 내에서 무한 루프를 실행하는 경우 함수가 종료되지 않음을 의미하기 때문에 값을 반환하지 못한다.
+
+### never에 다른 특징을 알아보자!
+
+never 타입은 모든 타입의 하위 타입으로 never 자신을 제외한 어떤 타입도 never 타입에 할당될 수 없다.
+조건부 타입을 결정할 때 특정 조건을 만족하지 않는 경우, 엄격한 타입 검사 목적으로 명시적으로 사용하기도 한다.
+
+
+
+
+## 5) Array 타입
+
+배열 타입을 나타내는 Array 키워드는 자바스크립트에서도 `Object.prototype.toString.call(...)` 연산자를 사용해 확인할 수 있다.
+
+`Object.prototype.toString.call(...)`은 객체 타입을 알아내는 데 사용하는 함수로, typeof의 경우 객체 타입을 단순히 object 타입으로 알려주지만 `Object.prototype.toString.call(...)` 함수는 객체의 인스턴스까지 알려준다.
+
+```ts
+const arr = [];
+console.log(Object.prototype.toString.call(arr)); // [object Array]
+```
+
+### 왜 타입스크립트에서 배열을 다뤄야할까?
+
+1. 자바스크립트에서는 배열은 객체에 속하는 타입이다. (배열을 단독 배열이라는 자료형에 국한하지 않는다.)
+2. 타입스크립트에서 Array 타입을 사용하기 위해 특수한 문법을 함께 다뤄야 한다.
+
+### 배열보다 더 좁은 범위인 튜플(Tuple)도 있다!
+
+배열은 Array 키워드와 대괄호([])를 사용해 직접 타입을 명시할 수 있는데, 이때 타입은 배열보다 더 좁은 범위인 튜플이다.
+
+### 다른 언어에서는 배열을 어떻게 다룰까?
+
+타입스크립트 뿐만 아니라 자바, C++과 같은 정적 언어에서는 배열의 원소로 하나의 타입만 사용하도록 명시한다.
+
+배열을 선언할 때 크기까지 제한하기도 하는데 타입스크립트에서는 배열의 크기까지 제한하지 않지만
+정적 특성을 살려 명시적인 타입을 선언하여 **해당 타입의 원소를 관리하는 것을 강제**한다.
+
+```ts
+const arr: number[] = [1, 2, 3]; // 숫자 원소만 허용
+const arr: Array = [1, 2, 3]; // 위와 동일한 타입
+```
+
+- 자료형 + 대괄호([]) 형식으로 배열 타입 선언
+- 제네릭 방식으로 배열 타입 선언
+
+> 두 방식의 차이점은 선언 형식 외에는 없다.
+
+```ts
+const arr1: Array = [1, "1"];
+const arr2: number[] | string[] = [1, "1"];
+const arr3: (number | string)[] = [1, "1"];
+```
+
+여러 타입을 모두 관리해야 하는 배열을 선언하려면 유니언 타입을 사용하면 된다.
+
+### 배열 기능에 길이 제한을 추가하려면?
+
+튜플이라는 배열 하위 타입으로 길이 제한을 추가하면 된다. 대괄호 안에 타입 시스템을 기술하고, 대괄호 안에 선언하는 타입 개수가 튜플이 가질 수 있는 원소의 개수이다.
+
+즉, 튜플은 배열의 특정 인덱스에 정해진 타입을 선언하는 것과 같다. 튜플을 이용해 사전에 허용하지 않은 타입이 서로 섞이는 것을 방지해 타입 안정성을 제공한다.
+
+```ts
+let tuple: [number] = [1]; // ✅
+tuple = [1, 2]; // ❌
+tuple = [1, "1"]; // ❌
+
+let tuple: [number, string, boolean] = [1, "1", true]; // ✅
+```
+
+> 튜플의 경우 컨벤션을 잘 지키고 각 배열 원소의 명확한 의미와 쓰임을 보장할 때 더욱 안전하게 쓸 수 있는 타입이다.
+
+### 리액트 훅을 예시로 튜플 사용 예시를 살펴보자!
+
+리액트 16.8 버전부터 도입된 훅이라는 요소 중 useState는 튜플 타입을 반환한다.
+
+1. 첫 번째 원소는 훅으로 부터 생성 및 관리되는 상태 값을 의미한다.
+2. 두 번째 원소는 해당 상태를 조작할 수 있는 세터를 의미한다.
+
+> useState API는 배열 원소의 자리마다 명확한 의미를 부여하기 때문에 컴포넌트에서 사용하지 않은 값에 접근하는 오류를 방지할 수 있다. 또 구조 분해 할당을 사용해 사용자가 자유롭게 이름을 정의할 수 있다.
+
+```ts
+import { useState } from "react";
+
+const [value, setValue] = useState(false);
+```
+
+### 튜플과 배열의 성질을 혼합해 사용할 수 있다!
+
+스프레드 연산자(...)를 사용해 특정 인덱스에서 요소를 명확한 타입으로 선언할 수 있다.
+이후 나머지 인덱스에서는 배열처럼 동일한 자료형의 원소를 개수 제한 없이 받도록 할 수 있다.
+
+```ts
+const example: [number, string, ...number[]] = [1, "1", 2, 3, 4];
+```
+
+### 옵셔널 프로퍼티(선택적 속성)를 명시하고 싶을 때는?
+
+물음표(?) 기호와 함께 해당 속성을 선언할 수 있다. 해당 원소는 옵셔널하기 때문에 해당 인덱스에 필수적으로 자리 잡고 있지 않음을 의미한다.
+
+> **옵셔널(optional)?**
특정 속성 또는 매개변수가 값이 있을 수도 없을 수도 있는 것을 의미한다. 선택적 속성은 타입스크립트에서 좀 더 유연한 데이터 모델링과 사용자 정의 타입을 지원하기 위한 개념이다.
+
+```ts
+const tuple1: [number, number?] = [1, 2];
+const tuple2: [number, number?] = [1];
+```
+
+
+
+
+## 6) enum 타입
+
+enum 타입은 열거형으로 부르는데 일종의 구조체를 만드는 타입 시스템이다.
+
+- enum 사용으로 열거형을 정의할 수 있는데 열거형은 각각의 멤버를 가지고 있다.
+- 타입스크립트는 명명한 각 멤버의 값을 스스로 추론한다.
+- 기본적인 추론 방식은 숫자 0부터 1씩 늘려가며 값을 할당하는 것이다.
+
+```ts
+enum Names {
+ kim, // 0
+ lee, // 1
+ park, // 2
+ chu, // 3
+ oh, // 4
+}
+
+// 각 멤버 접근 방식은 객체 속성 접근 방식과 동일
+Names.chu; // 3
+Names["chu"]; // 3
+
+// 역방향 접근도 가능하다
+Name[3]; // "chu"
+```
+
+### 각 멤버에 명시적 값 할당도 가능하다!
+
+명시적 값을 할당할 수도 있지만 일부 멤버에 값을 직접 할당하지 않아도
타입스크립트는 누락된 멤버를 이전 멤버 값의 숫자 기준으로 1씩 늘려가며 자동으로 할당한다.
+
+```ts
+enum Names {
+ kim = "kim",
+ lee = "lee",
+ park = 100,
+ chu, // 101
+ oh, // 102
+}
+```
+
+### 주로, enum은 언제 쓰일까?
+
+문자열 상수를 생성하는 데 사용해 응집력있는 집합 구조체를 만들 수 있다.
+이를 통해 사용자 입장에서도 간편하게 활용하고, 열거형 그 자체로 변수 타입으로도 지정할 수 있다.
+
+이때, 열거형을 타입으로 가지는 변수는 **해당 열거형이 가지는 모든 멤버를 값으로 받을 수 있다.**(코드의 가독성을 높여주는 효과!)
+
+### 아래 예시에서 enum을 사용해 얻을 수 있는 효과를 문자열 타입 지정과 비교해보자!
+
+```ts
+enum StatusType {
+ HOLD = "HOLD",
+ READY = "READY",
+ DELIVERING = "DELIVERING",
+ DELIVERED = "DELIVERED",
+}
+
+const checkItemStatus = (itemStatus: StatusType) => {
+ switch (itemStatus) {
+ case StatusType.HOLD:
+ case StatusType.READY:
+ case StatusType.DELIVERING:
+ return false;
+
+ case StatusType.DELIVERED:
+ default:
+ return true;
+ }
+};
+```
+
+1. 타입 안정성: StatusType에 명시되지 않은 다른 문자열은 인자로 받을 수 없다.
+2. 명확한 의미 전달과 높은 응집력 : StatusType이 다루는 값이 명확하고, 상태에 대한 값을 모아있는 것이라 응집력이 높다.
+3. 가독성: 응집도가 높기 때문에 말하는 바가 명확하다. 열거형 멤버를 통해 어떤 상태를 나타내는 지 쉽게 이해 가능하다.
+
+### 주의할 점은 없을까?
+
+숫자로만 이루어져 있거나 타입스크립트가 자동으로 추론한 열거형은 안전하지 않은 결과를 낳을 수 있다.또, 역방향으로 접근하더라도 타입스크립트는 이를 막지 않는다.
+
+### 그럴 때 const enum을 사용한다!
+
+역방향 접근을 허용하지 않아 자바스크립트에서의 객체에 접근하는 것과 유사한 동작을 보장하지만
숫자 상수로 관리되는 열거형은 선언한 값 이외의 값을 할당하거나 접근할 때 이를 방지하지 못한다.
+
+반면 문자열 상수 방식으로 선언한 열거형은 미리 선언하지 않은 멤버로 접근을 방지할 수 있어
문자열 상수 방식으로 열거형을 사용하는 것이 숫자 상수 방식보다 안전한다.
+
+의도하지 않은 값의 할당이나 접근을 방지하는 데 도움이 된다.
+
+```ts
+const enum NUMBER {
+ ONE = 1,
+ TWO = 2,
+}
+
+const num: NUMBER = 100; // Error! (확인 필요)
+
+const enum STRING {
+ ONE = "1",
+ TWO = "2",
+}
+
+const strNum: STRING = "3"; // Error!
+```
+
+> 현재 코드에서는 `const num: NUMBER = 100;` 해당 부분도 동일하게 에러가 난다. 왜 에러가 나는 지 깊이 파보자!!
+
+### 이외에도 열거형의 가장 큰 문제가 있다!
+
+타입스크립트 코드가 자바스크립트 코드로 변환될 때 `즉시 실행 함수(IIFE) `형식으로 변환된다.
+
+```ts
+enum Direction {
+ Up,
+ Down,
+ Left,
+}
+```
+
+```js
+"use strict";
+var Direction;
+(function (Direction) {
+ Direction[(Direction["Up"] = 0)] = "Up";
+ Direction[(Direction["Down"] = 1)] = "Down";
+ Direction[(Direction["Left"] = 2)] = "Left";
+})(Direction || (Direction = {}));
+```
+
+일부 번들러에서 트리쉐이킹 과정 중 즉시 실행 함수로 변환된 값을 사용하지 않는 코드로 인식하지 못하는 경우가 발생할 수 있어 불필요한 코드의 크기가 증가하는 결과가 생길 수 있다.
+
+이런 문제를 해결하기 위해 `const enum` 또는 `as const assertion`을 사용해 유니온 타입으로 열거형과 동일한 효과를 얻는 방법이 있다.
+
+### as const assertion으로 활용해보자!
+
+```ts
+const Color = {
+ RED: "red",
+ BLUE: "blue",
+} as const;
+
+const color: (typeof Color)[keyof typeof Color] = Color.RED;
+
+console.log(color);
+```
+
+```js
+"use strict";
+const Color = {
+ RED: "red",
+ BLUE: "blue",
+};
+const color = Color.RED;
+console.log(color);
+```
+
+Color는 단순한 객체로 변환되어 ✅ 트리 쉐이킹이 가능하다.
diff --git "a/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.2_\355\203\200\354\236\205_\354\241\260\355\225\251/seulgi.md" "b/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.2_\355\203\200\354\236\205_\354\241\260\355\225\251/seulgi.md"
index 3beced8..ec0273a 100644
--- "a/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.2_\355\203\200\354\236\205_\354\241\260\355\225\251/seulgi.md"
+++ "b/CH03_\352\263\240\352\270\211_\355\203\200\354\236\205/3.2_\355\203\200\354\236\205_\354\241\260\355\225\251/seulgi.md"
@@ -1 +1,359 @@
-
+# 타입 조합
+
+타입 검사 심화 버전을 알아보자!
+
+
+
+
+## 1) 교차 타입(intersection)
+
+교차 타입을 사용하면 여러 가지 타입을 결합해 하나의 단일 타입으로 만들 수 있다.
+기존에 존재하는 다른 타입을 합쳐 모든 멤버를 가지는 새로운 타입을 생성하는 것이다.
+
+- 교차 타입은 &을 사용해서 표기한다.
+- 결과물로 탄생한 단일 타입에는 타입 별칭을 붙일 수 있다.
+- 여러 개의 타입을 교차시킬 수도 있다.
+
+```ts
+type Me = {
+ name: string;
+ age: number;
+ location: string;
+ isWork: boolean;
+};
+
+type MyInfo = Me & { address: string };
+```
+
+> Me 타입의 변수를 선언하고 값을 할당하면 Me타입의 모든 멤버와 address까지 가지게 된다.
+
+
+
+
+## 2) 유니온 타입(union)
+
+유니온 타입은 타입 A 또는 타입 B 중 하나가 될 수 있는 타입이며 A | B 같이 표기한다.
+주로 특정 변수가 가질 수 있는 타입을 전부 나열하는 용도로 사용된다.
+
+교차 타입과 마찬가지로 2개 이상의 타입을 이어 붙일 수 있고,
+타입 별칭을 통해 중복을 줄일 수 있다.
+
+```ts
+type Me = {
+ name: string;
+ age: number;
+ location: string;
+ isWork: boolean;
+};
+
+type You = {
+ name: string;
+ age: number;
+ location: string;
+ areMarried: boolean;
+};
+
+type Info = Me | You;
+
+const printInfo = (info: Info) => {
+ console.log(info.location);
+ console.log(info.areMarried); // Error!
+};
+```
+
+> 해당 함수 내부에서 areMarried 속성을 참조하려고 하면 에러가 발생하는데, 이는 areMarried가 한 속성에만 존재하기 때문이다.
+
+### 맨 앞에 & 혹은 |를 붙이는 경우를 알아보자!
+
+교차 타입과 유니온 타입은 여러 줄에 걸쳐 표기할 수 있는데,
+이럴 때 각 줄의 맨 앞에 & 혹은 |를 붙여서 표기하면 된다.
+
+
+
+
+## 3) 인덱스 시그니처(Index Signatures)
+
+인덱스 시그니처는 특정 타입의 속성 이름을 알 수 없지만 속성값의 타입을 알고 있을 때 사용하는 문법이다.
+
+인터페이스 내부에 `[Key: K]: T` 꼴로 타입을 명시한다. 이는 해당 타입의 속성 키는 모두 K타입이어야 하고 속성값은 모두 T타입을 가져야한다는 뜻이다.
+
+```ts
+interface IndexSignature1 {
+ [key: string]: number;
+}
+
+interface IndexSignature2 {
+ [key: string]: number;
+ length: number;
+ isValid: boolean; // Error!
+ name: string; // Error!
+}
+```
+
+> 인덱스 시그니처를 선언할 때 다른 속성을 추가로 명시해줄 수 있는데 이때 추가로 명시된 속성은 인덱스 시그니처에 포함되는 타입이어야 한다.
+
+
+
+
+## 4) 인덱스드 엑세스 타입(Indexed Access Types)
+
+인덱스드 엑세스 타입은 다른 타입의 특정 속성이 가지는 타입을 조회하기 위해 사용된다.
+인덱스에 사용되는 타입 또한 그 자체로 타입이기 때문에 유니온 타입, keyof, 타입 별칭 등의 표현을 사용할 수 있다.
+
+```ts
+type Example = {
+ a: number;
+ b: string;
+ c: boolean;
+};
+
+type IndexedAccess = Example["a"]; // 인덱스드 엑세스 타입
+type IndexedAccess1 = Example[keyof Example]; // number | string | boolean
+```
+
+배열의 요소 타입을 조회하기 위해 인덱스드 엑세스 타입을 사용하는 경우가 있다.
+
+1. number로 인덱싱해 배열 요소를 얻는다.
+2. typeof 연산자를 붙여준다.
+3. 해당 배열 요소의 타입을 가져올 수 있다.
+
+```ts
+const People = [
+ { name: "a", age: 1 },
+ { name: "b", age: 2 },
+ { name: "c", age: 3 },
+];
+
+type PeopleOf = (typeof People)[number];
+
+// type People = { name: string; age: number }
+type PeopleType = PeopleOf;
+```
+
+> 해당 예시는 현재 에러가 난다. (확인 필요)
+
+
+
+
+## 5) 맵드 타입(Mapped Types)
+
+자바스크립트의 map은 배열 A를 기반으로 한 타입을 선언할 때 사용하는 문법인데, 인덱스 시그니처 문법을 사용해서 반복적인 타입 선언을 효과적으로 줄일 수 있다.
+
+```ts
+type Example = {
+ a: number;
+ b: string;
+ c: boolean;
+};
+
+type Subset = {
+ [K in keyof T]?: T[K];
+};
+
+const aExample: Subset = { a: 3 };
+const bExample: Subset = { a: 4, c: true };
+```
+
+- 맵드 타입에서 매핑할 때는 readonly와 ?를 수식어로 적용할 수 있다.
+- 맵드 타입의 특이한 점은 수식어 제거도 가능하다.
+
+```ts
+type ExampleType = {
+ readonly a: number;
+ readonly b: string;
+};
+
+type CreateMutable = {
+ -readonly [Property in keyof Type]: Type[Property];
+};
+type ResultType = CreateMutable; // { a: number; b: string }
+```
+
+### BottomSheet같은 예시로 알아보자.
+
+바텀 시트마다 각각의 resolver, isOpen 등의 상태를 관리하는 스토어가 필요한데 이 스토어의 타입을 선언해줘야 한다.
+
+BottomSheetMap에 존재하는 모든 키에 대해 일일이 스토어를 만들어 줄 수 있지만 불필요한 반복이 발생하게 된다.
+
+> 이럴 때는 인덱스 시그니처 문법을 사용해서 BottomSheetMap을 기반으로 각 키에 해당하는 스토어를 선언해 불필요한 반복을 줄여준다.
+
+```ts
+const BottomSheetMap = {
+ RECENT_CONTACTS: RecentContactsBottomSheet,
+ CARD_SELECT: CardSelectBottomSheet,
+ SORT_FILTER: SortFilterBottomSheet,
+ PRODUCT_SELECT: ProductSelectBottomSheet,
+ REPLY_CARD_SELECT: ReplyCardSelectBottomSheet,
+ RESEND: ResendBottomSheet,
+ STICKER: StickerBottomSheet,
+ BASE: null,
+};
+
+export type BOTTOM_SHEET_ID = keyof typeof BottomSheetMap;
+
+// 불필요한 반복이 발생한다
+type BottomSheetStore = {
+ RECENT_CONTACTS: {
+ resolver?: (payload: any) => void;
+ args?: any;
+ isOpened: boolean;
+ };
+ CARD_SELECT: {
+ resolver?: (payload: any) => void;
+ args?: any;
+ isOpened: boolean;
+ };
+ SORT_FILTER: {
+ resolver?: (payload: any) => void;
+ args?: any;
+ isOpened: boolean;
+ };
+ // ...
+};
+
+// Mapped Types를 통해 효율적으로 타입을 선언할 수 있다
+type BottomSheetStore = {
+ [index in BOTTOM_SHEET_ID]: {
+ resolver?: (payload: any) => void;
+ args?: any;
+ isOpened: boolean;
+ };
+};
+```
+
+### 맵드 + as 키워드로 키를 재지정 가능하다!
+
+```ts
+type BottomSheetStore = {
+ [index in BOTTOM_SHEET_ID as `${index}_BOTTOM_SHEET`]: {
+ resolver?: (payload: any) => void;
+ args?: any;
+ isOpened: boolean;
+ };
+};
+```
+
+> 위의 예시처럼 키 이름을 그대로 쓰거나 모든 키에 특정 문자열을 붙이는 것처럼 새로운 키를 지정할 수 있다.
+
+
+
+
+## 6) 템플릿 리터럴 타입(Template Literal Types)
+
+자바스크립트의 템플릿 리터럴 문자열을 사용하여 문자열 리터럴 타입을 선언할 수 있는 문법이다.
+
+```ts
+type Me = "chu" | "chuchu" | "seulgi" | "seulgi chu" | "chuseulgi";
+
+type MyName = `${Me}-name`;
+```
+
+- Me 타입의 모든 유니온 멤버 뒤에 -name을 붙여 새로운 유니온 타입을 만들었다.
+- 템플릿 리터럴을 사용하여 `${Me}-name`와 같이 변수 자리에 문자열 리터럴 유니온 타입인 Me를 넣으면 유니온 타입 멤버들이 차례로 해당 변수로 들어간다.
+- 해당 변수로 들어가 -name이 붙은 문자열 리터럴의 유니온 타입을 결과로 반환한다.
+
+
+
+
+## 7) 제네릭(Generic)
+
+제네릭은 C, 자바 같은 정적 언어에서 다양한 타입 간에 재사용성을 높이기 위해 사용하는 문법이다.
+
+### 제네릭의 사전적 의미를 알아보자!
+
+제네릭의 사전적 의미는 **특징이 없거나 일반적인 것**인데 타입스크립트의 제네릭도 이와 비슷한 맥락으로 일반화된 데이터 타입이라고 할 수 있다.
+
+- 함수, 타입, 클래스 등에서 내부적으로 사용할 타입을 정해두지 않고 타입 변수를 사용한다.
+- 변수로 해당 위치를 비워 둔 다음에, 실제로 그 값을 사용할 때 외부에서 타입 변수 자리에 타입을 지정해 사용하는 방식이다.
+
+> 이렇게 하면 함수, 타입, 클래스 등 여러 타입에 대해 하나하나 따로 정의하지 않아도 되기 때문에 재사용성이 크게 향상된다.
+
+### 제네릭 사용 방법을 알아보자!
+
+- ``와 같이 꺾쇠괄호 내부에 정의된다.
+- 사용할 때는 함수에 매개변수를 넣는 것과 유사하게 원하는 타입을 넣어주면 된다.
+- 타입 변수명으로 T(Type), E(Element), K(Key), V(Value) 등 한 글자로 된 이름을 많이 사용한다.
+
+```ts
+type Example = T[];
+
+const arr: Example = ["1", "2"];
+```
+
+### any와는 어떤 점이 다를까?
+
+any 타입의 배열에서는 배열 요소들의 타입이 전부 같지 않을 수 있다. 쉽게 말해 타입 정보를 잃어버린 것과 같다.
+
+반면 제네릭은 any처럼 아무 타입을 무분별하게 받는 게 아니라 배열 생성 시점에 원하는 타입으로 특정할 수 있는 것이다.
+
+> 제네릭을 사용하면 배열 요소가 전부 동일한 타입으로 보장될 수 있다.
+
+### 다른 특징은 뭐가 있을까?
+
+- 제네릭 함수를 호출할 때 반드시 꺾쇠괄호(<>) 안에 타입을 명시해야 하는 것은 아니다.
+- 타입을 명시하는 부분을 생략하면 컴파일러가 인수를 보고 타입을 추론한다.
+- 타입 추론이 가능한 경우는 타입 명시를 생략할 수 있다.
+
+```ts
+function example(arg: T): T[] {
+ return new Array(2).fill(arg);
+}
+
+example("hi"); // T는 string으로 추론
+```
+
+- 특정 요소 타입을 알 수 없을 때는 제네릭 타입에 기본값을 추가할 수 있다.
+
+```ts
+interface SubmitEvent extends SyntheticEvent {
+ submitter: T;
+}
+```
+
+### 특정 타입에서만 존재하는 멤버를 참조하려 하면 안된다!
+
+```ts
+function example(arg: T): number {
+ return arg.length; // Error!
+}
+```
+
+배열에만 존재하는 length 속성을 제네릭에서 참조하려고 하면 당연히 에러가 난다.
+
+컴파일러는 어떤 타입이 제네릭에 전달될지 알 수 없기 때문에 모든 타입이 length 속성을 사용할 수 없다 알려준다.
+
+```ts
+interface Example {
+ length: number;
+}
+
+function example(arg: T): number {
+ return arg.length;
+}
+```
+
+> 이럴 때는 제네릭 꺾쇠괄호 내부에 "length 속성을 가진 타입만 받는다"라는 제약을 걸어준다.
+
+### 제네릭을 사용할 때 주의해야 할 점이 있다?
+
+파일 확장자가 tsx일 때 화살표 함수에 제네릭을 사용하면 에러가 발생한다.
+
+tsx는 타입스크립트 + JSX이므로 제네릭의 꺾쇠괄호와 태그의 꺾쇠괄호를 혼동하여 문제가 생긴다.
+
+### 이런 상황을 어떻게 피할 수 있을까?
+
+제네릭 부분에 extends 키워드를 사용해 컴파일러에게 특정 타입의 하위 타입만 올 수 있음을 확실히 알려주면 된다.
+
+```ts
+// 에러 발생 : JSX element "T" has no corresponding closing tag.
+const exampleFunc = (arg: T): T[] => {
+ return new Array(3).fill(arg);
+};
+
+// 에러 발생 X
+const exampleFunc2 = (arg: T): T[] => {
+ return new Array(3).fill(arg);
+};
+```
+
+보통 제네릭을 사용할 때는 function 키워드로 선언하는 경우가 많다.
diff --git a/assets/CH03/typescript_structure.jpeg b/assets/CH03/typescript_structure.jpeg
new file mode 100644
index 0000000..a4c1466
Binary files /dev/null and b/assets/CH03/typescript_structure.jpeg differ