diff --git a/README.md b/README.md
index 2660f95..5bd7c34 100644
--- a/README.md
+++ b/README.md
@@ -26,9 +26,11 @@
│ ├── leo
│ ├── nibble
│ ├── paraffin
+│ ├── penguin
│ ├── perfume
│ ├── ramgee
│ ├── rebolution
+│ ├── reyou
│ ├── teasan
│ └── yell
│ ├── item6-8.md
@@ -39,7 +41,8 @@
```
-본인 닉네임에 다음과 같이 `.md`로 해당 아이템들을 요약 정리해서 올린다.
+- 본인 닉네임에 다음과 같이 `.md`로 해당 아이템들을 올린다.
+- 브랜치를 `본인 닉네임 / chapter2`으로 만들어서 요약 정리하고 그 챕터가 마무리가 된 뒤에 PR을 올리고 메인에 `merge`한다.
@@ -49,15 +52,23 @@
## 스터디 진행상황
+
+
| 2장 타입스크립트의 타입 시스템 | 스터디 진행한 날 | 완료 여부 |
-| ------------------------------ | ---------------- | --------- |
-| 아이템 6 - 8 | | |
-| 아이템 9 - 11 | | |
-| 아이템 12 - 14 | | |
-| 아이템 15 - 18 | | |
+| :----------------------------- | :--------------: | :-------: |
+| 아이템 6 - 8 | 2022-04-07 | ✅ |
+| 아이템 9 - 11 | 2022-04-14 | ✅ |
+| 아이템 12 - 14 | 2022-04-21 | ✅ |
+| 아이템 15 - 18 | 2022-04-28 | ✅ |
| 3장 타입 추론 | 스터디 진행한 날 | 완료 여부 |
-| -------------- | ---------------- | --------- |
-| 아이템 19 - 21 | | |
+| :------------: | :--------------: | :-------: |
+| 아이템 19 - 21 | 2022-05-12 | ✅ |
| 아이템 22 - 24 | | |
| 아이템 25 - 27 | | |
+
+| 4장 타입 설계 | 스터디 진행한 날 | 완료 여부 |
+| :------------: | :--------------: | :-------: |
+| 아이템 28 - 30 | | |
+| 아이템 31 - 33 | | |
+| 아이템 34 - 37 | | |
diff --git a/chapter2/biscuit/item12-14.md b/chapter2/biscuit/item12-14.md
new file mode 100644
index 0000000..a570085
--- /dev/null
+++ b/chapter2/biscuit/item12-14.md
@@ -0,0 +1,26 @@
+## 아이템 12. 함수 표현식에 타입 적용하기
+
+1. TypeScript에서는 함수 표현식을 사용하는것이 낫다. (expression)
+2. 함수의 매개변수 부터 리턴값까지 타입으로 선언해 함수 표현식에 재사용할 수 있다.
+3. 함수의 매개변수에 타입 선언을 하는 것보다 함수 표현식 전체 타입을 정의 하는것이 안전하다.
+4. 다른 함수를 참조하렴녀 typeof fn을 상요한다.
+
+---
+
+## 아이템 13. 타입과 인터페이스의 차이점 알기
+
+1. 인터페이스는 유니온 타입처럼 타입을 확장하지 못한다.
+2. 복잡한 타입을 확장하려면 타입과 & 를 상요한다.
+3. 인터페이스로 튜플과 비슷하게 구현하면 튜플에서 사용하는 concat같은 메서드를 사용할 수 없다.
+4. 튜플은 type으로 구현하는게 낫다.
+5. 선언 병합을 지원하기 위해선 인터페이스를 반드시 사용한다.
+
+---
+
+## 아이템 14. 타입 연산과 제너릭 사용으로 반복 줄이기
+
+1. 반복을 줄이는 가장 간단한 방법: 타입에 이름을 붙인다.
+2. extends를 사용해 인터페이스의 반복을 피한다.
+3. 제너릭 타입을 사용해 타입들간 매핑을 한다.
+
+---
diff --git a/chapter2/biscuit/item6-8.md b/chapter2/biscuit/item6-8.md
index 436715d..cfb2347 100644
--- a/chapter2/biscuit/item6-8.md
+++ b/chapter2/biscuit/item6-8.md
@@ -1,3 +1,26 @@
## 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
---
+
+1. 타입스크립트 컴파일러 tsc
+2. 타입스크립트 서버 tsserver
+
+타입스크립트 언어 서비스를 활용한다.
+타입 선언 파일을 찾아보는 습관을 만들자.
+
+---
+
+## 아이템 7. 타입이 값들의 집합이라고 생각하기
+
+- 타입스크립트가 오류를 체크하는 순간에 타입을 가진다.
+- 타입스크립트는 집합으로 표현할 수 있다.
+- A는 B를 상속, A는 B에 할당가능 은 A는 B의 부분집합이라는 뜻이다.
+
+---
+
+## 아이템 8. 타입 공간과 값 공간의 심벌 구분하기
+
+- 타입스크립트의 심벌은 타입 공간, 값 공간 중에 한 곳에 존재한다.
+- 심벌은 이름이 같아도 속하는 공간에 따라 다른 것을 나타낼 수 있다.
+- 값: &, | 는 비트연산, 타입 : &, | 는 인터섹션과 유니온
+-
diff --git a/chapter2/biscuit/item9-11.md b/chapter2/biscuit/item9-11.md
new file mode 100644
index 0000000..df3e5cf
--- /dev/null
+++ b/chapter2/biscuit/item9-11.md
@@ -0,0 +1,49 @@
+---
+
+## 아이템 9. 타입 단언보다는 타입 선언을 사용하기
+
+- 타입 단언을 하게 되면 잉여속석 체크가 적용되지 않는다.
+- 타입 단언은 강제로 타입을 지정했기 떄문에 타입 체커에게 오류를 무시하라라는것이다.
+- 타입스크립트는 DOM에 접근할 수 없다 => 이럴땐 타입 단언을 사용해주는게 맞다.
+- (!) 을 사용하면 null이 아니라는 단언문으로 해석된다.
+- 단언문은 컴파일 과정 중에 제거되어 타입 체커는 알 수 없다.
+- null이 아니라고 확신 할 수 있을때 사용한다.
+- 타입 단언문 타입 간에 변환을 할 수 없다.
+- HTMLElement는 HTMLElement | null 의 서브타입이므로 동작한다.
+- Person 과 HTMLElement는 서로의 서브타입이 아니기 떄문에 변환이 불가능하다.
+- 모든 타입은 unknown의 서브타입이므로 unknown이 포함된 단언문은 항상 동작한다.
+
+1. 타입 단언 (as Type) 보다는 타입 선언(: Type)을 사용한다.
+
+---
+
+## 아이템 10. 객체 래퍼 타입 피하기
+
+- javaScript의 기본형 (string,number,boolean,null,undefined,symbol)
+- 기본형은 불변형, 메서드를 가지지 않는다 로 객체와 구분할 수 있다.
+- string.charAt()등으로 메서드를 가지고 있는것 처럼 보인다.
+- string기본형은 메서드가 없지만 String객체 타입이 서로 자유롭게 변환된다.
+- string기본형에 chartAt메서드를 사용할때 js는 String객체로 래핑(wrap)하고 메서드를 호출하고 래핑한 객체를 버린다.
+- 객체 래퍼 타입의 자동 변환
+- number-Number / boolean-Boolean / symbol-Symbol / 기본형-래퍼타입
+- js에서 래퍼타입으로 기본형 값에서 메서드를 사용 할 수 있다.
+- TypeScript는 기본형과 객체 래퍼 타입을 별도로 모델링한다.
+- string을 사용할때는 특히 유의해야함 -> String이라고 잘못 타이핑 하기 쉽다.
+- string을 매개변수로 받는 메서드에 String객체를 전달 하면 문제가 생긴다.
+- (pharse:String) | 잘못된 예시
+- 'String'형식의 인수는 'string'형식의 매개변수에 할당 될 수 없습니다. error
+- striing은 String에 할당 할 수 있지만, String은 string에 할당 할 수 없다.
+- TypeScript가 제공하는 타입선언은 전부 기본형 타입으로 되어있다.
+
+1. 객체 래퍼타입은 지양하고 , 기본형 타입을 사용해야 한다. (String 대신 string, Number대신 number등)
+
+---
+
+## 아이템 11. 잉여 속성 체크의 한계 인지하기 (이해가 전반적으로 되지 않음..ㅠ)
+
+- TypeScript는 해당타입의 속성이 있는지, '그 외의 속성은 없는지' 확인한다.
+- TypeScript에서 잉여 속성 체크 과정이 수행된다.
+- document나 new HTMLAnchorElement는 객체 리터럴이 아니기 떄문에 잉여 속성 체크가 되지 않는다.
+- 잉여 속성 체크는 타입 단언문을 사용할 때에도 적용되지 않는다. => 타입 선언문을 사용해야하는 이유 중 하나.
+-
+-
diff --git a/chapter2/lado/item12-14.md b/chapter2/lado/item12-14.md
new file mode 100644
index 0000000..2df5e34
--- /dev/null
+++ b/chapter2/lado/item12-14.md
@@ -0,0 +1,384 @@
+# 이펙티브 타입스크립트 아이템 12~14
+
+## 아이템 12. 함수 표현식에 타입 적용하기
+
+- 타입스크립트에서는 함수 표현식을 사용하는 것이 좋다. 함수의 매개변수부터 반환값까지 전체를 함수 타입으로 선언하여 함수 표현식에 재사용할 수 있다는 장점이 있기 때문이다.
+
+ ```tsx
+ function rollDice(sides: number): number {
+ /* ... */
+ } // 문장
+ const rollDice2 = function (sides: number): numberg {
+ /* ... */
+ } // 표현식
+ const rollDice3 = (sides: number): number => {
+ /* ... */
+ } // 표현식
+
+ type DiceRollFn = (sides: number) => number
+ const rollDice: DiceRollFn = (sides) => {
+ /* ... */
+ }
+ ```
+
+- 함수 타입 선언의 장점
+
+ - 불필요한 코드의 반복을 줄인다.
+ - 함수 구현부가 분리되어 있어 로직이 보다 분명해진다.
+
+ ```tsx
+ function add(a: number, b: number) {
+ return a + b
+ }
+ function sub(a: number, b: number) {
+ return a - b
+ }
+ function mul(a: number, b: number) {
+ return a * b
+ }
+ function div(a: number, b: number) {
+ return a / b
+ }
+
+ type BinaryFn = (a: number, b: number) => number
+ const add: BinaryFn = (a, b) => a + b
+ const sub: BinaryFn = (a, b) => a - b
+ const mul: BinaryFn = (a, b) => a * b
+ const div: BinaryFn = (a, b) => a / b
+ ```
+
+- 시그니처가 일치하는 다른 함수가 있을 때도 함수 표현식에 타입을 적용하면 좋다.
+
+ ```tsx
+ const responseP = fetch('/quote?by=Mark+Twain') // 타입은 Promise
+
+ async function getQuote() {
+ const response = await fetch('/quote?by=Mark+Than')
+ const quote = await response.json()
+ return quote
+ }
+
+ // {
+ // "quote": "If you tell the truth, you don't have to remember anything.",
+ // "source": "notebook",
+ // "date": "1984"
+ // }
+
+ // lib.dom.d.ts에 있는 fetch의 타입 선언
+ declare function fetch(input: RequestInfo, init?: RequestInit): Promise
+
+ async function checkedFetch1(input: RequestInfo, init?: RequestInit) {
+ const response = await fetch(input, init)
+ if (!response.ok) {
+ // 비동기 함수 내에서 거절된 프로미스로 변환합니다.
+ throw new Error('Request failed: ' + response.status)
+ }
+ return response
+ }
+
+ // typeof fn을 사용해 fetch 함수의 시그니처 참조
+ const checkedFetch2: typeof fetch = async (input, init) => {
+ const response = await fetch(input, init)
+ if (!response.ok) {
+ throw new Error('Request failed: ' + response.status)
+ }
+ return response
+ }
+
+ // throw를 return으로 잘못 기재했을 때 타입 오류를 잡아냄
+ const checkedFetch3: typeof fetch = async (input, init) => {
+ // Type '(input: RequestInfo, init: RequestInit | undefined) => Promise' is not assignable to type '{ (input: RequestInfo, init?: RequestInit | undefined): Promise; (input: RequestInfo, init?: RequestInit | undefined): Promise<...>; }'.
+ // Type 'Promise' is not assignable to type 'Promise'.
+ // Type 'Response | Error' is not assignable to type 'Response'.
+ // Type 'Error' is missing the following properties from type 'Response': headers, ok, redirected, status, and 11 more.
+ const response = await fetch(input, init)
+ if (!response.ok) {
+ return new Error('Request failed: ' + response.status)
+ }
+ return response
+ }
+ ```
+
+
+
+## 아이템 13. 타입과 인터페이스의 차이점 알기
+
+- 타입스크립트에서 명명된 타입을 정의하는 방법은 두가지가 있다. 대부분의 경우에는 타입을 사용해도 되고 인터페이스를 사용해도 된다.
+
+```tsx
+type TState = {
+ name: string
+ capital: string
+}
+
+interface IState {
+ name: string
+ capital: string
+}
+```
+
+- (cf) 인터페이스 접두사로 I를 붙이는 것은 C#에서 비롯된 관례로, 지양해야 할 스타일이다.
+- 인터페이스 선언과 타입 선언의 비슷한 점
+
+ - 추가 속성과 함께 할당한다면 동일한 오류가 발생한다.
+
+ ```tsx
+ const wyoming: TState = {
+ name: 'Wyoming',
+ capital: 'Cheyenne',
+ population: 500_000,
+ // Type '{ name: string; capital: string; population: number; }' is not assignable to type 'TState'.
+ // Object literal may only specify known properties, and 'population' does not exist in type 'TState'.
+ }
+ ```
+
+ - 인덱스 시그니처는 인터페이스와 타입에서 모두 사용할 수 있다.
+
+ ```tsx
+ type TDict = { [key: string]: string }
+ interface IDict {
+ [key: string]: string
+ }
+ ```
+
+ - 함수 타입도 인터페이스나 타입으로 정의할 수 있다.
+
+ ```tsx
+ // 함수 타입에 추가적인 속성이 있을 때
+ type TFnWithProperties = {
+ (x: number): number
+ prop: string
+ }
+
+ interface IFnWithProperties {
+ (x: number): number
+ prop: string
+ }
+ ```
+
+ - 제너릭이 가능하다.
+
+ ```tsx
+ type TPair = {
+ first: T;
+ second: T;
+ }
+
+ interface IPair = {
+ first: T;
+ second: T;
+ }
+ ```
+
+ - 클래스를 구현할 때, 타입과 인터페이스 둘 다 사용할 수 있다.
+
+ ```tsx
+ class StateT implements TState {
+ name: string = ''
+ capital: string = ''
+ }
+
+ class StateI implements IState {
+ name: string = ''
+ capital: string = ''
+ }
+ ```
+
+ - 인터페이스는 타입을 확장할 수 있으며, 타입은 인터페이스를 확장할 수 있다.
+
+ ```tsx
+ interface IStateWithPop extends TState {
+ population: number
+ }
+
+ type TStateWithPop = IState & { population: number }
+
+ // 인터페이스는 유니온 타입 같은 복잡한 타입을 확장하지는 못한다.
+ // 복잡한 타입을 확장하고 싶다면 타입과 &를 사용해야 한다.
+ ```
+
+- 인터페이스 선언과 타입 선언의 차이점
+
+ - 유니온 타입은 있지만 유니온 인터페이스라는 개념은 없다.
+ - 인터페이스는 타입을 확장할 수 있지만, 유니온은 할 수 없다.
+ - 유니온 타입을 확장하는 게 필요한 경우
+ ```tsx
+ type Input = {
+ /* ... */
+ }
+ type Output = {
+ /* ... */
+ }
+ interface VariableMap {
+ [name: string]: Input | Output
+ }
+ ```
+ - 유니온 타입에 name 속성을 붙인 타입도 만들 수 있다.
+
+ ```tsx
+ type NamedVariable = (Input | Output) & { name: string }
+ ```
+
+ - type 키워드는 유니온이 될 수도 있고, 매핑된 타입 또는 조건부 타입 같은 고급 기능에 활용되기도 한다.
+ - 튜플과 배열 타입도 type 키워드를 이용해 더 간결하게 표현할 수 있다.
+
+ ```tsx
+ type Pair = [number, number]
+ type StringList = string[]
+ type NamedNums = [string, ...number[]]
+
+ // 인터페이스로 튜플과 비슷하게 구현할 수 있다. 하지만 그러면 튜플에서 사용할 수 있는 concat과 같은 메서드를 사용할 수 없다.
+ interface Tuple {
+ 0: number
+ 1: number
+ length: 2
+ }
+ ```
+
+ - 인터페이스는 보강(augment)이 가능하다.
+ - 선언 병합은 주로 타입 선언 파일에서 사용된다. 따라서 타입 선언 파일을 작성할 때는 선언 병합을 지원하기 위해 반드시 인터페이스를 사용해야 하며 표준을 따라야 한다.
+
+ ```tsx
+ // 선언 병합: 속성을 확장하는 것
+ interface IState {
+ name: string
+ capital: string
+ }
+
+ interface IState {
+ population: number
+ }
+
+ const wyoming: IState = {
+ name: 'Wyoming',
+ capital: 'Cheyenne',
+ population: 500_000,
+ } // 정상
+ ```
+
+- 타입과 인터페이스 중 어느 것을 사용해야 할까?
+
+ - 복잡한 타입이라면 타입 별칭
+ - 타입과 인터페이스, 두 가지 방법으로 모두 표현할 수 있는 간단한 객체 타입이라면 일관성과 보강의 관점에서 고려해 봐야 한다.
+ - 향후에 보강의 가능성이 있을지 생각해보고, 어떤 API에 대한 타입 선언을 작성해야 한다면 인터페이스를 사용하는 게 좋다. API가 변경될 때 사용자가 인터페이스를 통해 새로운 필드를 병합할 수 있어 유용하기 때문이다. 그러나 프로젝트 내부적으로 사용되는 타입에 선언 병합이 발생하는 것은 잘못된 설계이다.
+
+
+
+## 아이템 14. 타입 연산과 제너릭 사용으로 반복 줄이기
+
+- 더 큰 집합을 인덱싱해서 속성의 타입에서 중복 제거하기
+
+```tsx
+type TopNavState = {
+ userId: State['userId']
+ pageTitle: State['pageTitle']
+ recentFiles: State['recentFiles']
+}
+```
+
+- ‘매핑된 타입’을 사용해 중복 제거
+
+```tsx
+type TopNavState = {
+ [k in 'userId' | 'pageTitle' | 'recentFiles']: State[k]
+}
+
+type Pick = {
+ [k in K]: T[K]
+}
+
+type TopNavState = Pick
+```
+
+- 매핑된 타입과 keyof 사용해 선택적 필드로 바꾸기
+
+```tsx
+interface Options {
+ width: number
+ height: number
+ color: string
+ label: string
+}
+
+type OptionsUpdate = { [k in keyof Options]?: Options[k] }
+
+/*
+ interface OptionsUpdate {
+ width?: number;
+ height?: number;
+ color?: string;
+ label?: string;
+ }
+*/
+
+type OptionsKeys = keyof Options
+// 타입이 "width" | "height" | "color" | "label"
+
+type Partial = {
+ [P in keyof T]?: T[P]
+}
+```
+
+- 값의 형태에 해당하는 타입을 정의하고 싶을 때
+ - 값으로부터 타입을 만들어 낼 때는 선언의 순서에 주의해야 한다. 타입 정의를 먼저하고 값이 그 타입에 할당 가능하다고 선언하는 것이 좋다. 그렇게 해야 타입이 더 명확해지고, 예상하기 어려운 타입 변동을 방지할 수 있다.
+
+```tsx
+const INIT_OPTIONS = {
+ width: 640,
+ height: 480,
+ color: '#00FF00',
+ label: 'VGA',
+}
+
+type Options = typeof INIT_OPTIONS
+
+/*
+ interface Options {
+ width: number;
+ height: number;
+ color: string;
+ label: string;
+ }
+*/
+```
+
+- 함수나 메서드의 반환 값에 명명된 타입을 만들고 싶을 때
+
+```tsx
+function getUserInfo(userId: string) {
+ // ...
+ return {
+ userId,
+ name,
+ // ...
+ }
+}
+
+type UserInfo = ReturnType
+```
+
+- 제너릭 타입에서 매개변수를 제한할 수 있는 방법
+
+ - extends 사용
+
+ ```tsx
+ interface Name {
+ first: string
+ last: string
+ }
+
+ type DancingDuo = [T, T]
+
+ const couple: DancingDuo = [
+ { first: 'Fred', last: 'Astaire' },
+ { first: 'Ginger', last: 'Rogers' },
+ ]
+ ```
+
+ - Pick의 정의에서 타입 좁히기
+
+ ```tsx
+ type Pick = {
+ [k in K]: T[K]
+ }
+ ```
diff --git a/chapter2/lado/item15-18.md b/chapter2/lado/item15-18.md
new file mode 100644
index 0000000..5808da5
--- /dev/null
+++ b/chapter2/lado/item15-18.md
@@ -0,0 +1,190 @@
+## 아이템 15. 동적 데이터에 인덱스 시그니처 사용하기
+
+- 인덱스 시그니처
+ - 동적 데이터를 표현할 때 사용
+ ```tsx
+ type Rocket = { [property: string]: string }
+ const rocket: Rocket = {
+ name: 'Falcon 9',
+ variant: 'v1.0',
+ thrust: '4,940 kN',
+ } // 정상
+ ```
+ - 키의 이름 `property`
+ - 키의 위치만 표시하는 용도. 타입 체커에서는 사용하지 않음.
+ - 키의 타입 `string`
+ - string이나 number 또는 symbol의 조합이어야 하지만, 보통은 string을 사용.
+ - 값의 타입 `string`
+ - 어떤 것이든 될 수 있음.
+- 인덱스 시그니처의 4가지 단점
+ - 잘못된 키를 포함해 모든 키를 허용한다. 오타를 잡을 수 없다.
+ - 객체 안에 프로퍼티가 하나도 없는 {}도 유효한 타입이 된다.
+ - 키마다 다른 타입을 가질 수 없고, 키들의 타입이 통일되어야 한다.
+ - 키를 입력할 때 키에는 어떤 값도 들어올 수 있으므로 자동 완성 기능이 동작하지 않는다.
+- 인덱스 시그니처 대신 사용 가능한 2가지 대안
+ - `Record`
+ - 키 타입에 유연성을 제공하는 제너릭 타입
+ ```tsx
+ type Vec3D = Record<'x' | 'y' | 'z', number>
+ // type Vec3D = Record<키에 들어올 수 있는 타입, 값의 타입>;
+ // Type Vec3D = {
+ // x: number;
+ // y: number;
+ // z: number;
+ // }
+ ```
+ - 인덱스 시그니처의 파라미터 타입은 리터럴이 될 수 없다.
+ ```tsx
+ type fruitInfo = {
+ [fruit: '사과' | '딸기' | '포도']: number
+ }
+ // An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
+ ```
+ - 매핑된 타입 사용
+ - 키마다 별도의 타입을 사용하게 해준다.
+ ```tsx
+ type ABC = { [k in 'a' | 'b' | 'c']: k extends 'b' ? string : number }
+ // Type ABC = {
+ // a: number;
+ // b: string;
+ // c: number;
+ // }
+ ```
+- 런타임 때까지 객체의 속성을 알 수 없을 경우에만(예를 들어 CSV 파일에서 로드하는 경우) 인덱스 시그니처를 사용하도록 한다.
+- 안전한 접근을 위해 인덱스 시그니처의 값 타입에 undefined를 추가하는 것을 고려해야 한다.
+- 어떤 타입에 가능한 필드가 제한되어 있는 경우라면 인덱스 시그니처로 모델링하지 말아야 한다.
+ ```tsx
+ interface Row1 {
+ [column: string]: number
+ } // 너무 광범위
+ interface Row2 {
+ a: number
+ b?: number
+ c?: number
+ d?: number
+ } // 최선
+ type Row3 =
+ | { a: number }
+ | { a: number; b: number }
+ | { a: number; b: number; c: number }
+ | { a: number; b: number; c: number; d: number } // 가장 정확하지만 사용하기 번거로움
+ ```
+- 연관 배열(associative array)의 경우, 객체에 인덱스 시그니처를 사용하는 대신 Map 타입을 사용하는 것을 고려할 수 있다. ← 잘 이해는 안되지만 298페이지에 관련 내용 나온다고 함.
+
+
+
+## 아이템 16. number 인덱스 시그니처보다는 Array, 튜플, ArrayLike를 사용하기
+
+- 자바스크립트의 이상한 동작(feat. 암시적 타입 강제)
+ - 배열은 객체이므로 키는 숫자가 아니라 문자열이다.
+ - 자바스크립트에서는 숫자나 복잡한 객체를 키로 사용하려고 하면 문자열로 변환해 버린다.
+ - 배열에서 특정 요소를 접근할 때 인덱스를 문자열로 적어도 가능. 배열의 키를 Object.keys로 나열해보면 문자열로 출력된다.
+- 타입스크립트는 암시적 타입 강제의 혼란을 바로잡기 위해 숫자 키를 허용하고, 문자열 키와 다른 것으로 인식한다. (런타입에서는 문자열 키로 인식)
+- 인덱스를 신경 쓰지 않는다면, 배열을 순회할 때 `for...in` 보다 `for...of` 를 써라. 인덱스가 중요하다면 `forEach` 를 써라.
+
+ ```tsx
+ const xs = [1, 2, 3]
+
+ const keys = Object.keys(xs) // 타입이 stirng[]
+ for (const key in xs) {
+ key // 타입이 string
+ const x = xs[key] // 타입이 number
+ }
+
+ for (const x of xs) {
+ x // 타입이 number
+ }
+
+ xs.forEach((x, i) => {
+ i // 타입이 number
+ x // 타입이 number
+ })
+ ```
+
+ - `for...in` 은 `for...of` 나 `for` 루프보다 몇 배나 느리다.
+
+- 인덱스 시그니처에 number를 사용하기 보다 Array, 튜플, ArrayLike 타입을 사용하는 것이 좋다.
+- 어떤 길이를 가지는 배열과 비슷한 형태의 튜플을 사용하고 싶다면 타입스크립트에 있는 ArrayLike 타입을 사용한다.
+ ```tsx
+ const tupleLike: ArrayLike = {
+ '0': 'A',
+ '1': 'B',
+ length: 2,
+ }
+ ```
+
+
+
+## 아이템 17. 변경 관련된 오류 방지를 위해 readonly 사용하기
+
+- `readonly number[]` 와 `number[]` 가 구분되는 특징
+ - 배열의 요소를 읽을 수 있지만, 쓸 수는 없다.
+ - length를 읽을 수 있지만, 바꿀 수는 없다.
+ - 배열을 변경하는 pop을 비롯한 다른 메서드를 호출할 수 없다.
+ - `number[]` 는 `readonly number[]` 보다 기능이 많기 때문에 `readonly number[]` 의 서브 타입이 된다.
+- 매개변수를 readonly로 선언하면 아래와 같은 일이 생긴다.
+ - 타입스크립트는 매개변수가 함수 내에서 변경이 일어나는지 체크한다.
+ - 호출하는 쪽에서는 함수가 매개변수를 변경하지 않는다는 보장을 받게 된다.
+ - 호출하는 쪽에서 함수에 readonly 배열을 매개변수로 넣을 수도 있다.
+- 매개변수를 readonly로 선언할 때의 장점
+ - 더 넓은 타입으로 호출할 수 있고, 의도치 않은 변경은 방지될 것이다.
+ - 지역 변수와 관련된 모든 종류의 변경 오류를 방지할 수 있고, 변경이 발생하는 코드도 쉽게 찾을 수 있다.
+ - 함수가 매개변수를 수정하지 않는다면 readonly로 선언하는 것이 좋다. readonly 매개변수는 인터페이스를 명확하게 하며, 매개변수가 변경되는 것을 방지한다.
+- 단점?
+ - 어떤 함수를 readonly로 만들면 그 함수를 호출하는 다른 함수도 모두 readonly로 만들어야 한다. 다른 라이브러리에 있는 함수를 호출하는 경우라면 타입 선언을 바꿀 수 없기 때문에 타입 단언문을 사용해야 한다.
+- readonly, Readonly 제너릭은 얕게 동작한다는 것에 유의하며 사용해야 한다.
+
+ ```tsx
+ interface Outer {
+ inner: {
+ x: number
+ }
+ }
+
+ const o: Readonly = { inner: { x: 0 } }
+ o.inner = { x: 1 }
+ // Cannot assign to 'inner' because it is a read-only property.
+ o.inner.x = 1
+
+ type T = Readonly
+ // type T = {
+ // readonly inner: {
+ // x: number;
+ // };
+ // }
+ ```
+
+- 깊은 readonly 타입을 쓰고 싶으면 ts-essentials에 있는 DeepReadonly 제너릭을 사용하면 된다.
+- 인덱스 시그니처에도 readonly를 쓸 수 있다. 일기는 허용하되 쓰기를 방지하는 효과가 있다.
+ ```tsx
+ let obj: { readonly [k: string]: number } = {}
+ // 또는 Readonly<{[k: string]: number}>
+ obj.hi = 45
+ // Index signature in type '{ readonly [k: string]: number; }' only permits reading.
+ obj = { ...obj, hi: 12 }
+ ```
+
+
+
+## 아이템 18. 매핑된 타입을 사용하여 값을 동기화하기
+
+- 어떤 인터페이스에 속성이 추가될 때마다 다른 인터페이스의 속성도 같이 추가되어야 한다고 할 때 매핑된 타입을 사용해 값을 동기화하는 방식을 쓰는 것이 좋다.
+
+```tsx
+interface ScatterProps {
+ xs: number[]
+ ys: number[]
+ color: string
+ onClick: () => void
+ onDoubleClick: () => void
+}
+
+const REQUIRES_UPDATE: { [k in keyof ScatterProps]: boolean } = {
+ xs: true,
+ ys: true,
+ color: true,
+ onClick: false,
+}
+// Property 'onDoubleClick' is missing in type '{ xs: true; ys: true; color: true; onClick: false; }' but required in type '{ xs: boolean; ys: boolean; color: boolean; onClick: boolean; onDoubleClick: boolean; }'.
+// onDoubleClick 속성을 추가하라고 에러가 뜬다.
+```
diff --git a/chapter2/lado/item6-8.md b/chapter2/lado/item6-8.md
index 436715d..3a415cc 100644
--- a/chapter2/lado/item6-8.md
+++ b/chapter2/lado/item6-8.md
@@ -1,3 +1,160 @@
## 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
----
+- 타입스크립트를 설치하면, 다음 두 가지를 실행할 수 있다.
+ - 타입스크립트 컴파일러(tsc) → 주된 목적
+ - 단독으로 실행할 수 있는 타입스크립트 서버(tsserver) → 언어 서비스를 제공한다는 점에서 중요
+- 언어 서비스란
+ - 코드 자동 완성, 명세(사양, specification) 검사, 검색, 리팩터링 포함
+- 타입 추론 살펴보기
+ - 반환값의 타입을 명시하지 않으면 반환값의 타입을 어떻게 추론하는지 살펴보기
+ - 조건문의 분기에서 값의 타입이 어떻게 변하는지 살펴보기
+ - 객체의 개별 속성의 타입을 추론하는지 살펴보기
+ - 메서드 체인 중간의 추론된 제너릭 타입 살펴보기
+ - 타입 오류 살펴보기
+ - ex) typeof null이 “object”라 생기는 오류
+ - cf) `document.getElementById()` 의 경우 HTMLElement 뿐만 아니라 null도 올 수 있다.
+ - 라이브러리 타입 선언 살펴보기
+
+
+
+## 아이템 7. 타입이 값들의 집합이라고 생각하기
+
+- 타입: 할당 가능한 값들의 집합
+- null, undefined는 strictNullChecks 여부에 따라 number에 해당될 수도, 아닐 수도 있다.
+- 집합의 크기
+ - `naver` < `literal(unit)` < `union`
+- naver: 아무 값도 포함하지 않는 공집합. 아무 값도 할당할 수 없다.
+- literal(unit): 한 가지 값만 포함하는 타입 (ex) type A = ‘A’;
+- union: 값 집합들의 합집합. 2개 이상 (ex) type AB = ‘A’ | ‘B’
+- 타입스크립트 오류 중 ‘assignable’의 의미
+ - (ex) `Typescript: Type 'string | undefined' is not assignable to type 'string'`
+ - 집합의 관점에서 ‘~의 원소(값과 타입의 관계)’ 또는 ‘~의 부분 집합(두 타입의 관계)’을 의미한다.
+ - 타입 체커의 주요 역할은 하나의 집합이 다른 집합의 부분 집합인지 검사하는 것
+- `&` 연산자는 두 타입의 인터센션(교집합)을 계산한다.
+
+ - 타입 연산자는 인터페이스의 속성이 아닌 값의 집합(타입의 범위)에 적용된다.
+ - 인터섹션 타입의 값은 각 타입 내의 속성을 모두 포함하는 것이 일반적인 규칙이다. 하지만 두 인터페이스의 유니온에서는 그렇지 않다.
+ - 속성에 대한 인터섹션과 인터페이스의 유니온의 차이 이해하기
+
+ - 속성에 대한 인터섹션
+ 두 집합에서 필요로 하는 요건을 모두 만족시켜야 한다. 두 집합에서 가지고 있는 속성보다 더 많은 속성을 가지는 값도 타입에 속한다. (← 이 말 무슨 뜻인지..?)
+
+ ```tsx
+ interface Person {
+ name: string
+ }
+
+ interface Lifespan {
+ birth: Date
+ death?: Date
+ }
+
+ type PersonSpan = Person & Lifespan
+
+ // Type '{ name: string; }' is not assignable to type 'PersonSpan'. Property 'birth' is missing in type '{ name: string; }' but required in type 'Lifespan'
+ const me1: PersonSpan = {
+ name: '라도',
+ }
+
+ // 정상
+ const me2: PersonSpan = {
+ name: '라도',
+ birth: new Date('22/4/7'),
+ }
+
+ // Type '{ name: string; birth: Date; team: string; }' is not assignable to type 'PersonSpan'. Object literal may only specify known properties, and 'team' does not exist in type 'PersonSpan'.
+ const me3: PersonSpan = {
+ name: '라도',
+ birth: new Date('22/4/7'),
+ team: 'dev',
+ }
+ ```
+
+ - 인터페이스의 유니온
+
+ ```tsx
+ type K = keyof (Person | Lifespan) // type K = never
+ type K2 = keyof (Person & Lifespan) // type K2 = "name" | keyof Lifespan
+
+ // 정상
+ const keyOfMe: K2 = "name"
+
+ keyof (A|B) = (keyof A) & (keyof B)
+ keyof (A&B) = (keyof A) | (keyof B)
+ ```
+
+ - `extends` 를 사용해 서브 타입 만들기
+ - 제너릭 타입에서 한정자로 쓰임
+ - ‘A는 B를 상속’, ‘A는 B에 할당 가능’, ‘A는 B의 서브타입’은 ‘A는 B의 부분 집합’과 같은 의미이다.
+ - 타입스크립트를 집합으로 이해하기
+ | 타입스크립트 용어 | 집합 용어 |
+ | ---------------------------- | ----------------------------- | -------------------------- |
+ | never | ∅(공집합) |
+ | 리터럴 타입 | 원소가 1개인 집합 |
+ | 값이 T에 할당 가능 | 값 ∈ T (값이 T의 원소) |
+ | T1이 T2에 할당 가능 | T1 ⊆ T2 (T1이 T2의 부분 집합) |
+ | T1이 T2를 상속 | T1 ⊆ T2 (T1이 T2의 부분 집합) |
+ | T1 | T2 (T1과 T2의 유니온) | T1 ∪ T2 (T1과 T2의 합집합) |
+ | T1 & T2 (T1와 T2의 인터섹션) | T1 ∩ T2 (T1과 T2의 교집합) |
+ | unknown | 전체(universal) 집합 |
+
+
+
+## 아이템 8. 타입 공간과 값 공간의 심벌 구분하기
+
+- 타입스크립트의 심벌은 타입 공간이나 값 공간 중의 한 곳에 존재한다. 이름이 같더라도 어떨 땐 타입으로 쓰이고, 어떨 땐 값으로 쓰일 수 있다.
+
+```tsx
+interface Square {
+ width: number
+ height: number
+}
+
+const Square = (width: number, height: number) => ({ width, height })
+
+function calculateArea(shape: unknown) {
+ if (shape instanceof Square) {
+ shape.width // Property 'width' does not exist on type '{}'
+ }
+}
+```
+
+- instanceof는 자바스크립트의 런타임 연산자이고, 값에 대해서 연산을 한다. 그래서 `instanceof Square`는 타입이 아니라 함수를 참조한다.
+- type, interface, 타입 선언(:), 단언문(as) 다음에 나오는 심벌은 타입
+- const나 let 선언에 쓰이는 것, `=` 다음에 나오는 모든 것은 값
+- class와 enum은 타입과 값 두 가지 모두 가능한 예약어
+
+ - class가 타입으로 쓰일 때는 형태(속성과 메서드)가 사용되는 반면, 값으로 쓰일 때는 생성자가 사용된다.
+
+ ```tsx
+ class Square {
+ width = 1
+ height = 1
+ }
+
+ function calculateArea(shape: unknown) {
+ if (shape instanceof Square) {
+ // 값으로 쓰임
+ shape // 정상. 타입은 Square
+ shape.width // 정상. 타입은 number
+ }
+ }
+ ```
+
+- 연산자 중 타입에서 쓰일 때와 값에서 쓰일 때 다른 기능을 하는 것
+ - `typeof`
+ - 타입의 관점에서 typeof는 값을 읽어서 타입스크립트 타입을 반환한다. 타입 공간의 typeof는 보다 큰 타입의 일부분으로 사용할 수 있고, type 구문으로 이름을 붙이는 용도로도 사용할 수 있다.
+ - 값의 관점에서 typeof는 자바스크립트 런타임의 typeof 연산자가 된다. 값 공간의 typeof는 대상 심벌의 런타임 타입을 가리키는 문자열을 반환하며 타입스크립트의 타입과는 다르다.
+ - 클래스는 타입과 값 두 가지로 모두 사용되기 때문에 상황에 따라 다르게 동작
+ ```tsx
+ const v = typeof Square // 값이 "function" -> 클래스가 자바스크립트에서는 실제 함수로 구현되기 때문
+ type T = typeof Square // 타입이 typeof Square
+ ```
+- 타입의 속성을 얻을 때는 반드시 `obj['field']` 를 사용해야 한다.
+- 값으로 쓰이는 this는 자바스크립트의 this 키워드. 타입으로 쓰이는 this는, 일명 ‘다형성 this’라고 불리는 this의 타입스크립트 타입.
+- 값에서 &와 |는 AND와 OR 비트 연산. 타입에서는 인터섹션과 유니온
+- const는 새 변수를 선언하지만, as const는 리터럴 또는 리터럴 표현식의 추론된 타입을 바꾼다.
+- extends는 서브클래스(`class A extends B`) 또는 서브타입(`interface A extends B`) 또는 제너럴 타입의 한정자(`Generic`)를 정의할 수 있다.
+- in은 루프(`for (key in obj)`) 또는 매핑된 타입에 등장한다.
+- 모든 값은 타입을 가지지만, 타입은 값을 가지지 않는다.
+- “foo”는 문자열 리터럴이거나, 문자열 리터럴 타입일 수 있다.
diff --git a/chapter2/lado/item9-11.md b/chapter2/lado/item9-11.md
new file mode 100644
index 0000000..98c30a6
--- /dev/null
+++ b/chapter2/lado/item9-11.md
@@ -0,0 +1,129 @@
+# 이펙티브 타입스크립트 아이템 9~11
+
+## 아이템 9. 타입 단언보다는 타입 선언을 사용하기
+
+```tsx
+const alice: Person = { name: 'Alice' } // 타입 선언
+const bob = { name: 'Bob' } as Person // 타입 단언
+```
+
+- 타입 선언은 할당되는 값이 해당 인터페이스를 만족하는지 검사한다. 반면, 타입 단언은 강제로 타입을 지정했으니 타입 체커에게 오류를 무시하라고 하는 것이다.
+- 타입 단언이 꼭 필요한 경우가 아니라면, 안전성 체크도 되는 타입 선언을 사용하는 것이 좋다.
+- 타입 단언이 꼭 필요한 경우
+ - (ex) DOM 엘리먼트
+ ```tsx
+ document.querySelector('#myButton').addEventListener('click', (e) => {
+ e.currentTarget // 타입은 EventTarget
+ const button = e.currentTarget as HTMLButtonElement
+ button // 타입은 HTMLButtonElement
+ })
+ ```
+ - 타입스크립트는 DOM에 접근할 수 없기 때문에 #myButton이 버튼 엘리먼트인지 알지 못한다. 우리는 타입스크립트가 알지 못하는 정보를 가지고 있기 때문에 여기서는 타입 단언문을 쓰는 것이 타당하다.
+- 접미사로 쓰이는 `!` 는 null이 아니라는 단언문으로 해석
+- 모든 타입은 unknown의 서브타입이기 때문에 unknown이 포함된 단언문은 항상 동작한다. 하지만 unknown을 사용한 이상 적어도 무언가 위험한 동작을 하고 있다는 걸 알 수 있다.
+ ```tsx
+ const el = document.body as unknown as Person
+ ```
+- 화살표 함수의 반환 타입 선언하기
+ ```tsx
+ const people: Person[] = ['alice', 'bob', 'jan'].map((name): Person => ({ name }))
+ ```
+
+
+
+## 아이템 10. 객체 래퍼 타입 피하기
+
+- 자바스크립트에는 메서드를 가지는 String ‘객체’ 타입이 정의되어 있다. string ‘기본형’에는 메서드가 없지만, string 기본형에 charAt 같은 메서드를 사용할 때, 자바스크립트는 기본형을 String 객체로 래핑하고 메서드를 호출하고 마지막에 래핑한 객체를 버린다.
+ ```tsx
+ > x = "hello"
+ > x.language = 'English'
+ 'English' // x가 String 객체로 변환된 후 language 속성 추가
+ > x.language
+ undefined // language 속성이 추가된 객체 버려짐
+ ```
+ - (cf) 몽키-패치(monkey-patch): 런타임에 프로그램의 어떤 기능을 수정해서 사용하는 기법. 자바스크립트에서는 주로 프로토타입을 변경하는 것이 이에 해당.
+- 타입스크립트는 기본형과 객체 래퍼 타입을 별도로 모델링한다.
+- string을 String으로 잘못 타이핑하지 않도록 주의해야 한다.
+ - string을 매개변수로 받는 메서드에 String 객체를 전달하는 순간 문제가 발생한다.
+ ```tsx
+ function isGreeting(phrase: String) {
+ return ['hello', 'good day'].includes(phrase)
+ // Argument of type 'String' is not assignable to parameter of type 'string'.
+ // 'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible.
+ }
+ ```
+ - string은 String에 할당할 수 있지만 String은 string에 할당할 수 없다.
+- 기본형 타입은 객체 래퍼에 할당할 수 있기 때문에 타입스크립트는 기본형 타입을 객체 래퍼에 할당하는 선언을 허용한다. 하지만 오해하기 쉽기 때문에 기본형 타입을 사용하는 것이 낫다.
+ - new 없이 BigInt와 Symbol을 호출하는 경우는 기본형을 생성하기 때문에 사용해도 좋다.
+
+
+
+## 아이템 11. 잉여 속성 체크의 한계 인지하기
+
+- 타입이 명시된 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 속성이 있는지, 그리고 ‘그 외의 속성은 없는지’ 확인한다.
+- 잉여 속성 체크가 할당 가능 검사와는 별도의 과정이라는 것을 알아야 타입스크립트 타입 시스템에 대한 개념을 정확히 잡을 수 있다.
+- 아래의 예제에서는 구조적 타입 시스템에서 발생할 수 있는 중요한 종류의 오류를 잡을 수 있도록 ‘잉여 속성 체크’라는 과정이 수행되었다.
+
+ ```tsx
+ interface Room {
+ numDoors: number
+ ceilingHeightFt: number
+ }
+
+ const r: Room = {
+ numDoors: 1,
+ ceilingHeightFt: 10,
+ elephant: 'present',
+ // Type '{ numDoors: number; ceilingHeightFt: number; elephant: string; }' is not assignable to type 'Room'.
+ // Object literal may only specify known properties, and 'elephant' does not exist in type 'Room'
+ }
+ ```
+
+- 통상적인 할당 가능 검사에서는 obj가 Room 타입의 부분 집합을 포함하므로 에러가 발생하지 않는다.
+
+ ```tsx
+ interface Room {
+ numDoors: number
+ ceilingHeightFt: number
+ }
+
+ const obj = {
+ numDoors: 1,
+ ceilingHeightFt: 10,
+ elephant: 'present',
+ }
+
+ const r: Room = obj
+ ```
+
+- 엄격한 객체 리터럴 체크
+ - 객체 리터럴을 변수에 할당하거나 함수에 매개변수로 전달할 때 잉여 속성 체크가 수행된다.
+ - 잉여 속성 체크를 이용하면 타입 시스템의 구조적 본질을 해치지 않으면서도 객체 리터럴에 알 수 없는 속성을 허용하지 않음으로써 속성 이름의 오타 같은 실수를 잡을 수 있다.
+ - 객체 리터럴이 아닌 경우, 잉여 속성 체크가 적용되지 않는다. 즉, 임시 변수를 도입하면 잉여 속성 체크를 건너뛸 수 있다.
+ - 타입 단언문을 사용할 때에도 잉여 속성 체크가 적용되지 않는다.
+ - 객체 리터럴을 변수에 할당할 때, 잉여 속성 체크를 회피하는 방법
+ - 인덱스 시그니처를 통해 추가적인 속성 예상하기 <- 과연 이것은 적절한 방법일까..?
+ ```tsx
+ interface Options {
+ darkMode?: boolean
+ [otherOptions: string]: unknown
+ }
+ const o: Options = { darkmode: true } // 정상
+ ```
+- 선택적 속성만 가지는 ‘약한’ 타입
+
+ - 모든 속성이 선택적인 타입은 구조적 관점에서 모든 객체를 포함할 수 있다. 이런 약한 타입에 대해서 타입스크립트는 값 타입과 선언 타입에 공통된 속성이 있는지 확인하는 별도의 체크를 수행한다.
+ - 잉여 속성 체크와 마찬가지로 오타를 잡는 데 효과적이다.
+ - 잉여 속성 체크와 다르게, 약한 타입과 관련된 할당문마다 수행된다. 임시 변수를 제거하더라도 공통 속성 체크는 여전히 동작한다. **← ⁇⁇⁇**
+
+ ```tsx
+ interface LineChartOptions {
+ logscale?: boolean
+ invertedYAxis?: boolean
+ areaChart?: boolean
+ }
+
+ const opts = { logScale: true }
+ const o: LineChartOptions = opts
+ // Type '{ logScale: boolean; }' has no properties in common with type 'LineChartOptions'.
+ ```
diff --git a/chapter2/leo/images/typescript-diagram.png b/chapter2/leo/images/typescript-diagram.png
new file mode 100644
index 0000000..b5144f9
Binary files /dev/null and b/chapter2/leo/images/typescript-diagram.png differ
diff --git a/chapter2/leo/item6-8.md b/chapter2/leo/item6-8.md
index 436715d..e0282e5 100644
--- a/chapter2/leo/item6-8.md
+++ b/chapter2/leo/item6-8.md
@@ -1,3 +1,181 @@
-## 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
+# 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
----
+IDE에서 타입스크립트를 사용하기 위해서는 타입스크립트를 아래와 같이 전역으로 설치하면
+
+```bash
+$ npm install -g typescript
+# or
+$ yarn global add typescript
+```
+
+다음과 같이 크게 2가지 기능을 실행할 수 있다.
+
+- 타입스크립트 컴파일러(tsc)
+- 타입스크립트 서버(tsserver)
+
+일반적으로 타입스크립트 컴파일러를 실행하는 것이 주요 목적이지만 타입스크립트 서버 또한 '언어 서비스'를 제공한다는 점에서 유용하다. 대부분의 IDE도 비슷하겠지만 [VSC 기준](https://code.visualstudio.com/docs/typescript/typescript-compiling)으로 언어 서비스는 코드 자동완성, 명세 검사, 검색, 리팩토링을 제공한다.
+
+## IDE에서 타입스크립트 서버를 활용하는 방법
+
+- 심벌 위에 마우스 커서를 대면 타입스크립트가 해당 타입을 어떻게 판단하고 있는 지 확인할 수 있다.
+- 라이브러리를 사용할 때 해당 함수나 클래스에 대한 타입 선언을 알아보기 원한다면 `Go to Definition` 옵션을 사용해서 `*.d.ts`으로 이동해서 자세한 내용을 확인할 수 있다.
+
+## 정리
+
+- IDE의 언어 서비스 기능을 활용해서 타입스크립트가 현재 어떻게 어디까지 타입을 잘 추론하고 있는지 파악하자.
+- 특정 라이브러리의 함수나 클래스의 타입 선언 파일을 유연하게 확인하는 방법을 익히자.
+
+
+
+# 아이템 7. 타입이 값들의 집합이라고 생각하기
+
+타입스크립트에서 타입들을 집합 혹은 범위라고 생각하면 이해하기가 수월해진다. 타입을 할당할 때 항상 넓은 범위의 집합에서 좁은 범위의 집합으로는 할당이 절대 불가능하다고 생각하자! 마치 넓은 집에서 살다가 좁은 집으로 이사가면 답답해서 살 수 없는 것처럼 말이다.
+
+
+
+## never 타입
+
+never 타입은 타입스크립트에서 가장 작은 집합으로 아무것도 포함하지 않는 공집합이다.
+
+```ts
+const leo: never = "Leo"; // error: "Leo" 형식은 "never" 형식에 할당할 수 없습니다.
+```
+
+## 리터럴 타입
+
+리터럴(Literal) 타입은 유닛(Unit) 타입이라고도 불리는 타입스크립트에서 두 번째로 작은 집합으로 한 가지 값만 포함하는 타입이다.
+
+```ts
+type Leo = "Leo";
+type Ryan = "Ryan";
+```
+
+## 유니온 타입
+
+유니온(Union) 타입은 2개 이상의 타입을 묶을 때 `|`로 이어서 사용하며 값 집합의 합집합을 일컫는다.
+
+```ts
+type LeoAndRyan = Leo | Ryan;
+const friendLikeLion: LeoAndRyan = "Leo"; // Good!!
+const friendLikeLion: LeoAndRyan = "Apeach"; // error: "Apeach"는 "LeoAndRyan" 형식에 할당할 수 없습니다.
+```
+
+## 인터섹션 타입
+
+인터섹션(Intersection) 타입은 2개 이상의 타입의 교집합을 일컫고 `&`로 이어서 사용한다.
+
+아래의 예시에서 교집합이라는 단어만 생각하면 `Person`과 `FrontEnd` 타입의 교집합은 공집합이라고 잘못 이해할 수 있지만 값의 **집합**으로 생각해보면 두 타입의 속성을 모두 가지는 타입이 인터섹션 타입이다. 이 점을 주의하자!!
+
+```ts
+type Person = {
+ name: string;
+ birth: Date;
+};
+
+type FrontEnd = {
+ skills: string[];
+};
+
+type FE_Developer = Person & FrontEnd;
+
+const Ryan: FE_Developer = {
+ name: "Ryan",
+ birth: new Date("2014/10/01"),
+ skills: ["C++", "JS", "TS"],
+};
+```
+
+하지만 위와 같이 선언하는 것보다 아래와 같이 인터페이스의 상속의 사용하는 방법이 일반적이다.
+
+```ts
+interface Person = {
+ name: string;
+ birth: Date;
+};
+
+interface FE_Developer extends Person = {
+ skills: string[];
+};
+
+
+const Ryan: FE_Developer = {
+ name: "Ryan",
+ birth: new Date("2014/10/01"),
+ skills: ["C++", "JS", "TS"],
+};
+```
+
+## 타입과 집합의 용어 정리
+
+| 타입스크립트 용어 | 집합 용어 |
+| ------------------- | ------------------- |
+| never | 공집합 |
+| 리터럴 타입 | 원소가 1개인 집합 |
+| 값이 T에 할당 가능 | 값이 T의 원소 |
+| T1이 T2에 할당 가능 | T1이 T2의 부분 집합 |
+| T1이 T2를 상속 | T1이 T2의 부분 집합 |
+| T1 \| T2 | T1과 T2의 합집합 |
+| T1 & T2 | T1과 T2의 교집합 |
+
+## 정리
+
+- 타입을 값들의 집합으로써 생각하면 이해하기 쉬워진다. 항상 집합 및 범위 관점에서 타입의 할당을 바라보도록 하자.
+
+
+
+# 아이템 8. 타입 공간과 값 공간의 심벌 구분하기
+
+타입스크립트의 심벌(Symbol)은 타입 공간이나 값 공간 중의 한 곳에 존재한다. 타입 공간은 타입스크립트 컴파일러에 의해 컴파일된 이후에 사라지는 코드를 의미하며 남아 있는 코드는 값 공간을 의미한다.
+
+```ts
+type Leo = "Leo"; // 컴파일 이후에 사라질 타입 공간
+const Ryan = "Ryan"; // 컴파일 이후에 남아있을 값 공간
+```
+
+## 타입 공간과 값 공간에서 혼용되는 키워드들
+
+`typeof`, `this` 이외에도 많은 다른 연산자들과 키워드들이 타입 공간과 값 공간에서 다른 목적으로 사용된다.
+
+### typeof
+
+타입 공간에서 `typeof`는 값을 읽어서 타입스크립트의 타입을 반환하고 값 공간에서는 자바스크립트 런타임의 연산자가 된다.
+
+```ts
+type Person: {
+ name: string;
+}
+
+const p: Person = {
+ name: "Leo",
+}
+
+type NewPerson = typeof p; // NewPerson의 타입은 Person
+
+const v = typeof p; // v는 "object"
+```
+
+### this
+
+타입 공간에서 `this`는 `this`의 타입스크립트 타입이고 값 공간에서는 자바스크립트의 `this` 키워드가 된다.
+
+### const와 as const
+
+`const`는 새 변수를 선언하지만 `as const`는 리터럴 또는 리터럴 표현식의 추론된 타입을 바꾼다.
+
+### extends
+
+`extends`는 서브클래스(`class A extends B`), 서브타입(`interface A extends B`), 제너릭 타입의 한정자(`Generic`)를 정의할 수 있다.
+
+### in
+
+`in`은 루프(`for (key in object)`) 또는 매핑된(mapped) 타입에 등장한다.
+
+## 정리
+
+- 타입스크립트 코드를 읽을 때 타입 공간과 값 공간을 구분하는 방법을 익히도록 하자.
+- `class`와 `enum` 같은 키워드는 타입과 값으로 모두 사용될 수 있다는 것에 유의하자.
+- `"foo"`는 문자열 리터럴이거나 문자열 리터럴 타입일 수 있으므로 잘 구별하도록 하자.
+
+# 참조
+
+- https://www.oreilly.com/library/view/programming-typescript/9781492037644/ch03.html
diff --git a/chapter2/penguin/item12-14.md b/chapter2/penguin/item12-14.md
new file mode 100644
index 0000000..b1be905
--- /dev/null
+++ b/chapter2/penguin/item12-14.md
@@ -0,0 +1,433 @@
+# Item 12 - 함수 표현식에 타입 적용하기
+
+> 함수의 "문장" 과 "표현식" 은 다르다. 타입스크립트에서는 "표현식"을 사용하는 것이 좋다.
+
+함수 표현식을 사용하면,
+함수의 **매개변수** 부터 **반환값** 까지 전체를 함수 타입으로 선언하여 함수 표현식에 재사용이 가능하다.
+
+```
+type DiceRollFn = (sides:number) => number;
+
+const rollDice: DiceRollFn = sides =>{...}
+```
+
+함수 표현식을 사용하여 함수 타입을 선언하면 장점으로
+
+1. 함수 타입의 선언은 불필요 코드의 반복을 줄일 수있다.
+
+가령,
+
+```JS
+function add (a:number,b:number){return a + b;}
+function minus (a:number,b:number){return a - b;}
+function sub (a:number,b:number){return a * b;}
+function mul (a:number,b:number){return a / b;}
+```
+
+이러한 연산 함수 네 개의 타입은 **하나의 함수 타입으로 통합**할 수있다.
+
+```JS
+type BinaryFn = (a:number,b:number)=>number
+
+const add:BinaryFn = (a,b )=> a+b;
+const minus:BinaryFn = (a,b) =>a-b;
+const sub:BinaryFn = (a,b) => a*b;
+const mul:BinaryFn = (a,b )=> a/b;
+```
+
+`라이브러리는 공통 함수 시그니처를 타입으로 제공하기도 한다.` 예로, 리액트는 `MouseEvent` 타입 대신에, 함수의 매개변수에 명시하는 타입 대신 함수 전체에 적용할 수있는 `MouseEventHandler` 타입을 제공한다. ( => 와, 리액트에서 마우스 이벤트 핸들러 타입 다는게 귀찮다고만 생각했는데, 이게 리액트에서 제공되는 시그니처 타입이었구나. 몰랐다.)
+
+2. 시그니처가 일치하는 다른 함수가 있을 때도, 함수 표현식에 타입을 적용하면 이점이 있다.
+ 비동기 처리하는 fetch 함수가 있을 때,
+
+```JS
+const responseP = fetch("/quote?by=Mark_Twain"); //타입이 Promise
+
+async function getQuote(){
+
+const response = await fetch("/quote?by=Mark_Twain");
+const quote = await response.json();
+return quote;
+}
+
+```
+
+이때 만약 /quote 가 **존재하지 않는 API 라면**, JSON 형식이 아니라 "404 NOT FOUND"가 응답되어 올 수있다. 그러면, reponse 는 JSON 형식이 아니라는 오류메시지와 rejected 프로미스를 반환하게 된다.
+
+또한 **fetch 가 실패한 경우** 거절된 프로미스를 응답하지 않는다. 따라서 상태를 체크해 줄 checkedFetch
+함수를 작성해 보자.
+
+fetch의 타입 선언
+
+```JS
+declare function fetch(
+ input:RequestInfo, init?:RequestInit
+): Promise; //타입이 Promise
+```
+
+```JS
+async function checkedFetch(input:RequestInfo,init?:RequestInit){
+const response = await fetch(input,init);
+if(!response.ok){
+throw new Error("Request failed:" + response.status);
+}
+return response;
+}
+```
+
+위의 코드를 더 간결하게 표현식을 사용하면..
+checkedFetch 의 타입은 fetch (_typeof 는 피연산자의 평가 전 자료형을 나타내는 문자열을 반환하는데 이렇게도 사용된 것은 어떤 사용례 일지? fetch 의 자료형을 리턴해준..? [MDN-typeof](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/typeof_) => 찾아보니까 49p에서 JS와 TS 의 typeof 의 다른 기능에 대해 언급함 !)
+
+```JS
+const checkedFetch:typeof fetch = async(input,init)=>{
+const response = await fetch(input,init);
+if(!reponse.ok){
+ throw new Error("Request failed: "_ response.status);
+}
+return response;
+}
+```
+
+함수 문장을 함수 표현식으로 바꾸고, 함수 전체에 타입 (typeof fetch) 를 적용했다. `이는 타입스크립트가 input과 init 의 타입을 추론할 수있게 해준다.` 또한 함수 checkedFetch 의 반환타입을 보장해준다.
+이는 fetch 와 동일하다. (만약, throw 대신 return 을 했으면 TS 는 오류를 잡아낼것.)
+
+즉, 요약하면 함수 `매개변수` 가 아닌, 함수 `표현식 전체 타입을 정의` 하는 것이 코드적으로 간결하고 안전하다.
+
+> 즉, 다른 함수의 시그니처와 동일한 타입을 가지는 새 함수가 있는 경우, (동일 타입 시그니처를 가지는 중복의 함수가 있는 경우) 함수 작성시, 함수 전체의 타입 선언을 적용해야 한다.
+> ⭐ 다른 함수의 시그니처를 참조하려면 **typeof fn** 을 사용하면 된다.
+
+# Item 13 - 타입과 인터페이스의 차이점
+
+> TS 에서 타입을 정의하는 방법은 type, interface 두 가지가 있다. 두 방법은 어떤 차이가 있을까?
+
+(추측 : 타입 사용해서 정의한건,, 그냥 일반적인 타입 정의 방법 ? 인터페이스는 자바에서 본 건데,,음,,,어떤 공용으로 사용되는 타입을 정의할때 쓰는거 아닐까..?)
+
+```JS
+//type 을 사용한 타입 정의
+type TState = {
+ name: string;
+ capital: string;
+}
+
+//interface 를 사용한 타입 정의
+interface IState {
+ name:string;
+ capital:string;
+}
+```
+
+대부분의 경우, 타입, 인터페이스 둘 중 선택해서 사용해도 된다. 그러나 둘의 차이를 분명하게 알고,
+같은 상황에서는 동일한 방법으로 명명된 타입을 정의해 일관성을 유지 하도록 하자.
+( \*아, 참고로 위의 예제에서 T와 I 가 접두사로 붙는 것은 C#에서 비롯된 관례이나, 요즘엔 지양해야 할 스타일이다. )
+
+먼저 타입과 인터페이스의 **유사점은** 다음과 같다.
+
+1. [[인덱스 시그니처]]는 인터페이스와 타입에서 모두 사용할 수있습니다 (? 인덱스 시그니처가 뭐지)
+
+```JS
+type TDict = {[key:string]:string};
+
+interface IDict{
+ [key:string]:string;
+}
+```
+
+2. 함수 타입도 타입, 인터페이스 둘다 정의 가능하다.
+
+```JS
+type TFn = (x:number)=> string;
+interface IFn{
+ (x:number):string
+}
+
+const toStrT:Tfn = x => '' + x;
+const toStrI:Ifn = x => '' + x;
+```
+
+3. 함수 타입에 추가적인 속성이 있다면 , 타입이나 인터페이스 어떤 것을 선택하든 차이가 없다.
+
+```JS
+type TFnWithProperties = {
+ (x:number):number;
+ prop:string;
+}
+
+interface IFnWithProperties{
+ (x:number):number;
+ prop:string;
+}
+```
+
+문법이 낯설지만, 자바스크립트에서 함수는 호출 가능한 `객체` 라는 점을 염두하면 이해할 수있다.
+
+4. 타입 별칭과 인터페이스는 모두 [[제너릭]]이 가능하다.
+
+```JS
+type TPair={
+ first:T;
+ second:T;
+}
+
+interface IPair{
+ first:T;
+ second:T;
+}
+```
+
+5. 인터페이스는 타입을 확장할 수있으며, 타입은 인터페이스를 확장 할 수있다.
+
+```JS
+interface IStateWithPop extends Tstate{
+ population:number;
+}
+type TStateWithPop = IStateWithPop & {population:number} //책에는 IState로만 되어있는데 IStateWithPop 맞겠지?
+```
+
+그러나 인터페이스는 유니온 타입과 같은 복잡한 타입은 확장하지 못한다. 복잡한 타입을 확장하고싶다면, 타입과 & 를 사용해야 한다.
+
+6. 클래스를 구현(implements) 할 때는 타입과, 인터페이스 둘 다 사용이 가능하다.
+
+```JS
+class StateT implements TState{
+ name:string="";
+ capital:string ="";
+}
+
+class StateI implements IState{
+ name:string="";
+ capital:string="";
+}
+```
+
+타입과 인터페이스의 **차이점** 들은다음과 같다.
+
+1. 유니온 타입은 있지만, 유니온 인터페이스라는 개념은 없다.
+
+```JS
+type AorB = "A" | "B"
+```
+
+인터페이스 또한 타입을 확장할 수는 있다. 그러나 유니온은 할 수 없다.
+즉,
+
+```JS
+type Input={}
+type OutPut ={}
+
+interface VariableMap{
+ [name:string] : Input | Output
+}
+```
+
+Input, Output 타입을 하나의 변수명으로 매핑하는 VariableMap 인터페이스
+(name이 string 형이고 input, output, 객체타입 갖는..? TS 코드 구현을 많이 안해봐서
+그런지 코드 이해가 잘 안된다.)
+
+```JS
+type NameVariable = (Input | Output) & { name:string };
+```
+
+타입으로 하면, 유니온 타입에다가 name 이라고 하는 속성을 또 붙인 타입을 만들 수있다.
+
+이러한 표현은 인터페이스로는 불가능한다. 즉, type 으로 타입을 선언하는 것이, 일반적인 경우에서 interface 를 통한 정의보다 쓰임새가 많다.
+
+> type 사용의 장점
+
+1. union 이 가능하고,
+2. [[매핑된 타입]] 또는 조건부 타입 같은 고급 기능에 활용할 수있다.
+3. [[튜플]]과 [[배열]] 타입도 type 키워드로 더 간결하게 표현이 가능하다. (인터페이스로도 튜플 구현이 가능하나 concat 같은 메서드 사용이 불가능하다. 따라서 type 으로 구현해주는 것이 좋다.)
+
+```JS
+type Pair = [number,number];
+type StringList = string[];
+
+type NamedNums = [string,...number[]];
+```
+
+위처럼 [[튜플]] 을 type 을 사용하면 간결하게 표현 할 수있는데 반해
+인터페이스로는 다음과 같이 구현해야 한다. 또한 이렇게 구현해도 **concat 과 같은 메서드들은 사용할 수없다.**
+
+```JS
+interface Tuple{
+ 0:number;
+ 1:number;
+ length:2;
+}
+
+const t:Tuple = [10,20]
+```
+
+그럼 interface 로 타입정의할 때의 장점은 무엇일까?
+
+1. 보강(argument)이 가능하다. (타입엔 없는 기능.)
+
+```JS
+interface IState{
+ name:string;
+ capital:string
+}
+
+interface IState{
+ population:number;
+}
+
+const penguin:IState ={
+ name:"penguin",
+ capital:"North"
+ population:500_000
+};
+```
+
+위처럼 속성 확장하는 것을 `[[선언 병합(declaration merging)]]` 이라고 한다. 선언 병합을 지원하기 위해서 반드시 인터페이스를 사용해야한다.
+
+타입 선언할때, `사용자가 채워야 하는 빈틈` 이 있다면 선언 병합을 사용하여 채울 수있다.
+(<- 오 이런 점 궁금했었는데 인터페이스로 하면 해결이 되는구나! )
+
+타입은 기존 타입에 추가적인 보강이 없는 경우에만 사용해야 한다.
+
+결론적으로...
+
+- 복잡한 타입이라면 ? -> [[타입 별칭]]을 사용하면 된다.
+- 간단한 객체 타입이라면? -> 일관성과 보강의 관점에서 고려해 봐야 한다. (일관적으로 인터페이스를 사용하는 중이라면 인터페이스를, 타입을 사용중이라면 타입을 사용하면 된다.)
+
+예를 들어, API 에 대한 타입 선언을 작성해야 한다면, 인터페이스를 사용하는 것이 좋다.
+API 변경시 인터페이스를 통해 새로운 필드를 병합 할 수있기 때문임. 그러나 `프로젝트 내부적으로 사용되는 타입에 선언 병합이 생기는 것은 잘못된 설계`이다. 이럴 땐 타입을 사용하자.
+
+# Item 14 - 타입 연산과 제너릭 사용으로 반복 줄이기
+
+함수, 상수 , 루프의 반복을 제거하는 법을 알아보자.
+
+```JS
+console.log("Cylinder 1x1","surface area:",6.2424*1*1+6.2423*1*1,
+ "Volume:",3.14*1*1*1);
+
+console.log("Cylinder 1x2","surface area:",6.2424*1*1+6.2423*2*1,
+ "Volume:",3.14*1*2*1);
+
+console.log("Cylinder 2x1","surface area:",6.2424*1*1+6.2423*1*1,
+ "Volume:",3.14*2*2*1);
+
+```
+
+위의 원기둥 높이 표면적 부피를 출력하는 콘솔 코드를
+
+반복을 제거하여 다음과 같이 작성할 수있다.
+
+```JS
+const surfaceArea=(r,h)=> 2*Math.PI*r*(r+h);
+const volume = (r,h)=>Math.PI*r*r*r*h;
+
+for(const [r,h] of [[1,1],[1,2],[2,1]]){
+ console.log(
+ `Cylinder ${r}x ${h}`,
+ `Surface area: ${surfaceArea(r,h)}`,
+ `Volume: ${volume(r,h)}`);
+ )
+}
+```
+
+이렇게 개발자들이 코드의 중복을 제거하는 것 처럼, 타입에서도 또한 중복을 제거하는 것이 바람직하다.
+
+예를들어,
+
+```JS
+function distance(a:{x:number,y:number},b:{x:number,y:number}){
+ return Math.sqrt(Math.pow(a.x-b.x,2))+Math.pow(a.y-b.y,2);
+}
+```
+
+위와 같은 타입 중복은
+
+```JS
+interface Point2D{
+ x:number;
+ y:number;
+}
+
+function distance(a:Point2D,b:Point2D){...}
+
+```
+
+이런 식으로 반복되는 타입 중복을 줄일 수있다.
+
+또한 한 인터페이스가 다른 인터페이스를 `확장`하게 함으로써 반복을 제거 할 수있다.
+
+```JS
+interface Person{
+ firstName:string;
+ lastName:string;
+}
+
+interface PersonWithBirthDate extends Person{
+ birth:Date;
+}
+```
+
+또한 이미 존재하는 타입 확장의 경우 인터섹션 연산자를(&) 쓸 수도 있다. (일반적이진 않음)
+
+```JS
+type PersonWithBirthDate = Person & {birth:Date};
+```
+
+이 방법은 확장할 수없는 유니온 타입에 속성 추가를 하려고 할때 유용하다.
+
+- ⭐ 더 큰 집합을 인덱싱 하여 속성의 타입에서 중복을 제거하는 법을 알아보자
+
+```JS
+interface State{
+ userId:string;
+ pageTitle:string;
+ recentFiles:string[];
+ pageContents:string;
+}
+```
+
+```JS
+interface TopNavState{
+ userId:string;
+ pageTitle:string;
+ recentFiles:string[];
+}
+```
+
+위처럼 State의 타입의 [[부분집합]] 타입을 갖고 있는 TobNavState 가 있을 때, 어떻게 중복을 줄일 수있을까?
+
+State 를 **인덱싱** 하여 속성의 타입에서 중복을 제거할 수있다. (너무 신기해욘...)
+
+```JS
+type TopNavState = {
+ userId:State['userId'];
+ pageTitle:State['pageTitle'];
+ recentFiles:State['recentFiles'];
+}
+```
+
+이를 더욱 발전시켜보면, **매핑된 타입**을 사용할 수도 있다.
+
+```JS
+type TopNavState = {
+ [k in 'userId'|'pageTitle'|'recentFiles']:State[k]
+}
+```
+
+[[매핑된 타입]]은 배열 필드를 루프 도는 것과 같은 방식이며, 표준 라이브러리에서도 많이 쓰이는 패턴으로 **Pick** 이라고도 한다. (신기신기)
+
+```JS
+interface SaveAction{
+ type:"save";
+}
+
+interface LoadAction{
+ type:"load";
+}
+
+type Action = SaveAction | LoadAction;
+
+type ActionType = 'save'|'load'; //타입의 반복.
+
+// 💡 Action 유니온을 인덱싱 해주면 타입 반복 없이 ActionType을 정의가능하다.
+
+type ActionRec = Pick //{type:'save'|'load'}
+
+
+```
diff --git a/chapter2/penguin/item15-18.md b/chapter2/penguin/item15-18.md
new file mode 100644
index 0000000..2d3535d
--- /dev/null
+++ b/chapter2/penguin/item15-18.md
@@ -0,0 +1,195 @@
+# Item 15 - 동적 데이터에 인덱스 시그니처 사용하기
+> JS 의 장점. 객체를 생성하는 문법이 간단하다. 그래서 인덱스 시그니처도 가능하다..하지만..?
+
+JS 객체는 문자열 키를 `타입의 값과 관계없이 매핑이 가능`하다.
+이러한 속성으로 인해 타입스크립트에서 **인덱스 시그니처** 를 명시하여 유연하게 매핑을 표현할 수 있다.
+그러나 인덱스 시그니처를 사용한 타입 체크에는 단점도 존재한다.
+
+인덱스 시그니처의 예
+```JS
+type Rocket = {[property:string]:string};
+```
+- 키의 이름 - property : 키의 이름. 키의 위치만 표시함.
+- 키의 타입 - string 이나 number 또는 symbol 의 조합. 보통은 string 사용.
+- 값의 타입 - 어떤 것이든 가능
+
+인덱스 시그니처 타입의 사용 예
+```JS
+const rocket:Rocket ={
+name:'Peng',
+species:'bird',
+habitat:'antartic'
+}
+```
+
+- 인덱스 시그니처의 단점
+ - property에 모든 키가 들어갈 수 있음 (단순히 위치만 표시하는 역할이기 때문에)
+ - 특정 키가 필요하지 않음. {} 도 유효한 Rocket 타입임.
+ - 키마다 다른 타입을 갖는 것이 불가능하다. 위의 예시에서 보면 string값만 사용가능함
+ - 키가 무엇이든 사용할 수 있기 때문에, 자동 완성 기능이 동작 안함.
+
+
+인덱스 시그니처의 적절한 사용 - 동적인 데이터의 타입을 지정해 줘야 할때 고려해 볼만하다
+- 런타임 때까지 객체의 속성을 알 수없는 경우에 사용하자.
+- 인덱스 시그니처는 동적 데이터를 표현할 때 사용하자. 동적인 값이 들어와서 저장해서 사용하고 싶을 때. 인덱스 시그니처를 사용하거나 값 타입에 undefined 를 추가할 수 있다.
+
+#❓
+> 연관 배열(associative arr)의 경우 인덱스 시그니처 대신 Map타입 사용을 고려 가능.
+> 이는 프로토타입 체인과 관련된 문제를 우회한다 <- 이해안가지만..일단 여기까지...
+
+
+인덱스 시그니처의 대안
+- 선택적 필드, 유니온 타입으로 모델링, 인터페이스
+- [Record](https://typescript-kr.github.io/pages/utility-types.html#recordkt) 를 사용
+ - Record 는 키 타입에 유연성을 제공하는 제너릭 타입.
+ - 타입의 프로퍼티들을 다른 타입에 매핑하는데 사용할 수있다.
+
+- 매핑된 타입을 사용하는 방법.
+ - 키마다 별도의 타입을 사용 할 수있음
+
+```JS
+type MappingType ={[K in 'x'|'y'|'z']:number};
+
+type ABC = {[k in 'a'|'b'|'c']: k extends 'b'?string:number};
+```
+
+**🔹 결론**
+- 타입에 필드가 제한 & 지정되어있는 경우 인덱스 시그니처로 타입 모델링 하지 말자.
+- 키가 몇개인지 모른다면, **선택적 필드** 혹은 **유니온 타입**으로 모델링 할 것.
+- 안전한 접근을 위해 인덱스 시그니처 값 타입에 undefined 추가하는 것 고려하기.
+
+---
+
+# Item 16 - number 인덱스 시그니처보다 Array, 튜플, ArrayLike 사용하기.
+> 이상한 자바스크립트.. 암시적 타입 강제같은게 있다니..
+> 이것 때문에 객체 모델에 대한 이해가 필요할 수도있음. (아이템 10)
+
+자바스크립트에서 배열의 키를 나열해보면 키가 문자열로 출력이됨.
+```JS
+x = [1,2,3]
+Object.keys(x)
+
+=> 출력 결과
+['1','2','3'] 일줄 알았는데 ㅋ
+
+키 값이라
+['0', '1', '2'] 이렇게 나오넹 인덱스값? 인듯
+
+배열도 객체..(키/밸류)
+```
+
+타입스크립트에선, 숫자 키를 허용하고 문자열 키와 둘을 구분함. => Array에 대한 타입 선언
+
+인덱스에 신경쓰지 않으면 for in 보다 for of 를 사용 하는것이 더 좋다.
+타입이 불확실하면 for-in 루프는 for-of , for-루프에 비해 성능이 안좋다.
+
+⭐ 인덱스 시그니처가 number로 되어있으면 입력값은 number 가 되어야하지만...
+실제 JS 엔진이 키를 string 으로 변환하는 식으로 동작함.
+
+길이를 가지는 배열과 비슷한 형태의 튜플을 사용하고 싶으면, TS 의 ArrayLike 타입을 사용할 것. (물론 ArrayLike 사용해도 키가 여전히 문자열임.)
+
+**🔹 결론**
+- 배열이 객체여서 키가 숫자가 아니라 문자열임.
+- 인덱스 시그니처에 number 사용보다는 Array, 튜플, 또는 ArrayLike 타입 사용하는게 좋음.
+---
+
+# item 17 - 변경 관련된 오류 방지를 위해 readonly 사용하기
+
+>자바스크립트의 배열은 내용을 변경할 수있기 때문에, arraySum이 배열을 변경하지 않는다는 접근 제어자 readonly 를 사용하면 어떻게 될까...
+
+- 삼각수를 출력하는 함수
+```JS
+function printTri(n:number){
+
+const nums=[];
+
+for(let i=0;i void;
+}
+
+const REQUIRES_UPDATE: { [k in keyof ScatterProps]: boolean } = {
+ xs: true,
+ ys: true,
+ xRange: true,
+ yRange: true,
+ color: true,
+ onClick: false,
+};
+
+function shouldUpdate(oldProps: ScatterProps, newProps: ScatterProps) {
+ let k: keyof ScatterProps;
+ for (k in oldProps) {
+ if (oldProps[k] !== newProps[k] && REQUIRES_UPDATE) {
+ return true;
+ }
+ }
+ return false;
+}
+```
+
+
+**매핑된 타입**은 한 객체가 또 다른 객제와 정확히 같은 속성을 가지게 할 때 이상적이다. **인터페이스에 새로운 속성을 추가할 때, 선택을 강제하도록 매핑된 타입을 사용할 것인지 고려**해야 한다.
+
+**🔹 결론**
+- 매핑된 타입을 사용해서 관련된 값과 타입을 동기화하도록 한다.
+- 인터페이스에 새로운 속성을 추가할 때, 선택을 강제하도록 매핑된 타입을 고려하자.
+
+---
diff --git a/chapter2/perfume/item12-14.md b/chapter2/perfume/item12-14.md
new file mode 100644
index 0000000..c811b6f
--- /dev/null
+++ b/chapter2/perfume/item12-14.md
@@ -0,0 +1,132 @@
+## 💡 함수 표현식에 타입 적용하기
+
+자바스크립트와 타입스크립트에서는 함수 '문장(statement)'과 함수 '표현식(expression)'을 다르게 인식합니다.
+
+```
+function rollDice1(sides:number): nimber {}
+```
+
+위 코드는 문장(statement)입니다. 반면 아래 코드들은 함수 표현식입니다.
+
+```
+const rollDice2 = function(sides: number): number {};
+const rollDice3 = (sides: number) : number => {};
+```
+
+타입스크립트에서는 함수 표현식을 사용하는 것이 좋습니다. 함수의 매개변수부터 반환값까지 전체를 함수 타입으로 선언하여 함수 표현식에 재사용할 수 있기 때문입니다.
+
+type DiceRollFn = (sides: number) => number;
+const rollDice: DiceRollFn = sides => {};
+
+sides에 마우스를 올려 보면 이미 타입스크립트가 sides의 타입을 number로 인식하고 있다는 걸 알 수 있습니다.
+
+함수 타입의 선언은 불필요한 코드의 반복을 줄입니다.
+
+```
+function add(a:number, b: number) {return a + b};
+function sub(a:number, b: number) {return a - b};
+function mul(a:number, b: number) {return a * b};
+function div(a:number, b: number) {return a / b};
+
+```
+
+위의 코드처럼 반복되는 함수 시그니처를 일일이 적어줄 필요 없이 하나의 함수 타입으로 통합할 수도 있습니다.
+
+```
+type BinaryFn = (a:number, b: number) => number;
+const add: BinaryFn = (a,b) => a+b;
+const sub: BinaryFn = (a,b) => a-b;
+const mul: BinaryFn = (a,b) => a*b;
+const div: BinaryFn = (a,b) => a/b;
+```
+
+이처럼 함수의 매개변수에 타입 선언을 하는 것보다 함수 표현식 전체 타입을 정의하는 것이 코드도 간결하고 안전합니다. 다른 함수의 시그니처와 동일한 타입을 가지는 새 함수를 작성하거나, 동일한 타입 시그니처를 가지는 여러 개의 함수를 작성할 때는 매개변수의 타입과 반환 타입을 반복해서 작성하지 말고 함수 전체의 타입 선언을 적용해야 합니다.
+
+## 💡타입과 인터페이스의 차이점 알기
+
+타입스크립트에서 명명된 타입(named type)을 정의하는 두 가지 방법이 있습니다.
+
+1. type
+
+```
+type TState = {
+name: string;
+capital: string;
+}
+```
+
+2. interface
+
+```
+interface Istate {
+name: string;
+capital: string;
+}
+```
+
+대부분의 경우 두 가지 중 어느 것을 사용해도 상관 없습니다. 하지만 둘의 차이를 분명하게 알고, 같은 상황에서는 동일한 방법으로 명명된 타입을 정의해 일관성을 유지해야 합니다.
+
+그럼 둘의 차이가 뭘까요?
+
+인터페이스는 유니온 타입 같은 복잡한 타입을 확장하지는 못한다는 것입니다. 복잡한 타입을 확장하고 싶다면 타입과 &을 사용해야 합니다. 유니온 타입은 있지만, 유니온 인터페이스라는 개념은 존재하지 않죠. 그래서 type 키워드는 일반적으로 interface보다 쓰임새가 많습니다. type 키워드는 유니온이 될 수도 있고, 매핑된 타입 또는 조건부 타입 같은 고급 기능에 활용되기도 합니다.
+
+대신 인터페이스에는 타입에 없는 몇 가지 기능이 있습니다. 그중 하나가 바로 보강(augment)이 가능하다는 것입니다. 아까 interface를 설명할 때 등장했던 예제에 population 필드를 추가할 때 보강 기법을 사용할 수 있습니다.
+
+```
+interface Istate {
+name: string;
+capital: string;
+}
+
+interface Istate {
+population: number;
+}
+
+const wyoming: IState = {
+name: 'Wyoming',
+capital: 'Cheyenne',
+population: 500_000
+};
+
+```
+
+이 예제처럼 속성을 확장하는 것을 '선언 병합(declaration merging)'이라고 합니다. 선언 병합을 지원하기 위해서는 반드시 인터페이스를 사용해야 합니다.
+
+자, 그럼 타입과 인터페이스 중 어느 것을 사용하는 게 좋을까요?
+
+복잡한 타입이라면 고민할 것도 없이 타입 키워드를 사용하면 됩니다. 그러나 두 가지 방법으로 모두 표현할 수 있는 간단한 객체 타입이라면 일관성과 보강의 관점에서 고려해 봐야 합니다. 기존의 코드베이스에서 사용하는 키워드를 쓰는 것이 좋습니다.
+
+## 💡 타입 연산과 제너릭 사용으로 반복 줄이기
+
+같은 코드를 반복하지 말라는 DRY(don't repeat yourself) 원칙이 있습니다. 이 원칙은 타입에도 적용됩니다. 같은 타입을 반복해서 적어줄 필요는 없겠죠! 반복을 줄이는 가장 간단한 방법은 타입에 이름을 붙이는 것입니다. 예를 들어, 아래 코드처럼 몇 개의 함수가 같은 타입 시그니처를 공유하고 있다고 해 보겠습니다.
+
+```
+function get(url:string, opts: Options) : Promise {}
+function post(url:string, opts: Options) : Promise {}
+```
+
+위와 같은 경우 해당 시그니처를 명명된 타입으로 분리할 수 있습니다.
+
+```
+type HTTPFunction = (url:string, opts: Options) => Promise;
+const get: HTTPFunction = (url, opts) => {};
+const post: HTTPFunction = (url, opts) => {};
+
+```
+
+한 인터페이스가 다른 인터페이스를 확장하게 해서 반복을 제거할 수도 있습니다.
+
+```
+interface Person {
+firstName: string;
+lastName: string;
+}
+
+interface PersonWithBirthDate extends Person {
+birth: Date;
+}
+```
+
+이처럼 extends를 사용하면 인터페이스 필드의 반복을 피할 수 있습니다.
+
+뿐만 아니라 우리에게는 제너릭이 있습니다. 제너릭 타입은 타입을 위한 함수와 같습니다. 그리고 함수는 코드에 대한 DRY 원칙을 지킬 때 유용하게 사용됩니다. 따라서 타입의 반복을 줄이는 핵심에 제너릭이 있습니다. 타입을 반복하는 대신 제너릭 타입을 사용하여 타입들 간에 매핑을 하는 것이 좋습니다. 그런데 함수에서 매개변수로 매핑할 수 있는 값을 제한하기 위해 타입 시스템을 사용하는 것처럼, 제너릭 타입에서 매개변수를 제한할 수 있는 방법이 필요합니다. 그 방법은 바로 extends입니다. extends를 이용하면 제너릭 매개변수가 특정 타입을 확장한다고 선언할 수 있습니다.
diff --git a/chapter2/perfume/item15-18.md b/chapter2/perfume/item15-18.md
new file mode 100644
index 0000000..337d244
--- /dev/null
+++ b/chapter2/perfume/item15-18.md
@@ -0,0 +1,25 @@
+## 💡 동적 데이터에 인덱스 시그니처 사용하기
+
+런타임 때까지 객체의 속성을 알 수 없을 경우에만 인덱스 시그니처를 사용하는 것이 좋습니다.
+
+#### 🤔 인덱스 시그니처란?
+
+인덱스 시그니처는 {[키의 이름: 키의 타입]: 값의 타입} 과 같은 형태를 가진 타입 문법을 말합니다. 유연한 매핑을 표현할 수 있다는 장점을 가지고 있죠. 하지만 유연한만큼 잘못된 키를 포함한 모든 키를 허용한다는 단점이 있습니다.
+
+그래서 인덱스 시그니처의 값 타입에 undefined를 추가해서 안정성을 높이는 방법을 권장합니다. 하지만 더욱 추천하는 것은, 가능하다면 인터페이스나 Record, 매핑딘 타입 같은 인덱스 시그니처말고 정확한 타입을 사용하는 것입니다.
+
+## 💡 number 인덱스 시그니처보다는 Array, 튜플, ArrayLike 사용하기
+
+배열은 객체이므로 키는 숫자가 아니라 문자열입니다. 자바스크립트는 숫자를 키로 사용하는 것을 허용하지 않습니다. 숫자 인덱스를 사용해도 인덱스들이 문자열로 자동으로 변환되어 사용됩니다. 이런 혼란을 바로잡기 위해 타입스크립트는 숫자 키를 허용합니다. 하지만 인덱스 시그니처로 사용된 number 타입은 버그를 잡기 위한 순수 타입스크립트 코드입니다. 그러니 인덱스 시그니처에 number를 사용하기보다 Array, 튜플, ArrayLike를 사용하기를 권장합니다.
+
+## 💡 변경 관련된 오류 방지를 위해 readonly 사용하기
+
+만약 함수가 매개변수를 수정하지 않는다면 readonly로 선언하는 것이 좋습니다. readonly 매개변수는 인터페이스를 명확하게 하며, 매개변수가 변경되는 것을 방지합니다. 불변을 사랑하는 함수형 개발자들이 readonly를 사랑하는 것은 당연할 수 밖에 없습니다.
+
+readonly를 사용하게 되면 변경하면서 발생하는 오류를 방지할 수 있고, 변경이 발생하는 코드도 쉽게 찾을 수 있습니다.
+
+하지만 readonly는 얕게 동작한다는 것도 잊지 마세요!
+
+## 💡 매핑된 타입을 사용하여 값을 동기화하기
+
+매핑된 타입을 사용해 관련된 값과 타입을 동기화하도록 하세요. 새로운 속성이 추가될 때마다 값과 타입을 동기화시키면 타입 체커에게 보다 정확한 정보를 줄 수 있게 됩니다. 또한 매핑된 타입은 한 객체가 또 다른 객체와 정확히 같은 속성을 가지게 할 때 이상적입니다. 매핑된 타입을 이용하면 타입스크립트가 코드에 제약을 강제하도록 할 수 있습니다.
diff --git a/chapter2/perfume/item6-8.md b/chapter2/perfume/item6-8.md
index 436715d..c0a3d3b 100644
--- a/chapter2/perfume/item6-8.md
+++ b/chapter2/perfume/item6-8.md
@@ -1,3 +1,68 @@
-## 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
+## ✨ 타입스크립트의 타입 시스템
----
+오늘날 자바스크립트는 어엿한 모던 프로그래밍 언어로 자리 잡았습니다. 자바스크립트 프로그래머들을 고통스럽게 하던 타입 불안정성 문제 역시 타입스크립트라는 강력한 해결책의 등장으로 안정되었습니다. 타입스크립트의 등장이 자바스크립트의 완성도를 높이는 신의 한 수가 된 셈입니다.
+
+그렇다면 타입스크립트가 어떻게 자바스크립트의 타입 불안정성을 해결했을까요? 간단합니다. '타입'스크립트라는 이름처럼, 타입스크립트 컴파일러는 자바스크립트 코드의 타입 오류를 체크합니다.
+
+이번 글에서는 타입스크립트의 타입 시스템을 이해하는 방법을 간단하게 요약해서 설명하겠습니다. (자세한 내용은 책 '이펙티브 타입스크립트'를 참고하세요.)
+
+### 💡 타입이 값들의 집합이라고 생각하기
+
+자바스크립트의 런타임에는 단 6개의 타입만 존재합니다. 하지만 타입스크립트에는 무수히 많은 종류의 타입이 있습니다. 게다가 리터럴 타입과 유니온 타입, 타입의 상속(extends) 같은 낯선 개념이 타입에 대한 이해의 걸림돌이 되기도 합니다. 이를 보다 쉽게 이해하기 위해서, 타입을 값의 집합이라고 생각해봅시다.
+
+36.5, 7, 11, 8 등의 숫자는 number라는 집합에 들어갈 수 있습니다. 하지만 'cat'이라는 string 값은 number라는 집합에 들어갈 수 없겠죠. 집합이라고 표현했지만, 타입의 '범위'라고 이해하셔도 좋을 것 같네요.
+
+이와 같은 관점에서 봤을 때, 타입 체커의 주요 역할은 하나의 집합이 다른 집합의 부분 집합인지 검사하는 것이라고 볼 수 있습니다.
+
+타입스크립트의 타입은 엄격한 상속 관계가 아니라 겹쳐지는 집합으로 표현됩니다. 두 타입은 서로 서브타입이 아니면서도 겹쳐질 수 있습니다.
+
+타입 연산 역시 값의 집합(타입의 범위)에 적용됩니다. 또한 추가적인 속성을 가지는 값도 여전히 그 타입에 속합니다. 이 부분에선 간단한 예시 코드를 보겠습니다.
+
+```
+interface Person {
+name: string;
+}
+
+interface Lifespan {
+birth: Date;
+death?: Date;
+}
+
+type PersonSpan = Person & Lifespan;
+```
+
+언뜻 봤을 때는 Person과 Lifespan 인터페이스는 공통으로 가지는 속성이 없기 때문에 PersonSpan 타입이 공집합(never 타입)처럼 보일 수 있습니다. PersonSpan의 범위를 오렌지색으로 표현한다면 아래 그림 같을 거라고 생각하기 때문이죠.
+
+
+
+하지만 실제로는 다음 그림에 가깝습니다.
+
+
+
+그래서 아래와 같은 코드가 정상적으로 작동합니다.
+
+```
+const ps: PersonSpan = {
+name: 'Hedy Lamarr',
+birth: new Date('1914/11/09'),
+death: new Date('2000/01/19').
+};
+```
+
+(앞의 세 가지보다 더 많은 속성을 가지는 값도 PersonSpan 타입에 속합니다.)
+
+타입이 집합이라는 관점은 이외의 다른 개념들도 명확하게 이해할 수 있도록 돕습니다. 'A는 B를 상속', 'A는 B에 할당 가능', 'A는 B의 서브타입' 등의 말은 결국 A는 B의 부분 집합이라는 뜻입니다.
+
+### 💡 타입 공간과 값 공간의 심벌 구분하기
+
+타입스크립트 코드를 읽을 때 타입인지 값인지 구분하는 방법을 터득해야 합니다. 타입스크립트의 심벌(symbol)이 타입 공간이나 값 공간 중 한 곳에 존재하기 때문입니다. 이름이 같더라도 심벌이 속하는 공간에 따라 다른 것을 나타낼 수 있기 때문에 이 부분이 혼란스러울 수 있습니다.
+
+모든 값은 타입을 가지지만, 타입은 값을 가지지 않습니다. type과 interface 같은 키워드는 타입 공간에만 존재합니다.
+
+class나 enum 같은 키워드는 타입과 값 두 가지로 사용될 수 있습니다.
+
+> 💛 조금 다른 이야기인데요, 타입스크립트에서 enum을 되도록 사용하지 않는 것이 좋다고 합니다. 이에 관한 자세한 내용은 [이 글](https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking/)을 참조하세요.
+
+typeof, this 그 외의 여러 연산자들과 키워드들은 타입 공간과 값 공간에서 다른 목적으로 사용될 수 있습니다.
+
+그래서 타입스크립트 코드가 잘 동작하지 않는다면 타입 공간과 값 공간을 혼동해서 잘못 작성했을 가능성이 큽니다. 이를 구분하는 방법을 터득하기 위해서 타입스크립트 플레이그라운드를 활용해 개념을 잡으면 좋을 것 같네요!
diff --git a/chapter2/perfume/item9-11.md b/chapter2/perfume/item9-11.md
new file mode 100644
index 0000000..8d8fca2
--- /dev/null
+++ b/chapter2/perfume/item9-11.md
@@ -0,0 +1,51 @@
+### 💡 타입 단언보다는 타입 선언을 사용하기
+
+지난 글에서 타입 스크립트를 사용하는 이유는 타입 안정성을 높이기 위해서라고 말한 적이 있습니다. 보다 높은 타입 안정성을 위해, 타입 단언보다는 타입 선언을 사용하는 것이 좋습니다. 왜 그런지 아래 코드를 함께 살펴보며 확인해봅시다.
+
+```
+interface Cat {name: string};
+
+const cherie: Cat = {name: 'Cherie'}; // 타입은 Cat
+const homie = {name: 'Homie'} as Cat; // 타입은 Cat
+```
+
+첫 번째 cherie: Cat은 타입 선언입니다. 변수에 타입 선언을 붙여서 그 값이 선언된 타입임을 명시하는 방법이죠. 두 번째 as Cat은 타입 단언입니다. 말 그대로 타입을 '단언'했기 때문에 타입 스크립트가 추론한 타입이 있더라도 그걸 무시하고 Cat 타입으로 간주합니다. 그래서 아래와 같은 일이 일어납니다.
+
+```
+const cherie: Cat = {};
+```
+
+위 코드를 작성할 경우 'Cat' 유형에 필요한 'name' 속성이 없다는 에러 메시지가 뜹니다. 타입 스크립트가 할당되는 값이 해당 인터페이스를 만족하는지 검사했기 때문입니다. 반면 아래 코드는 에러가 발생하지 않습니다.
+
+```
+const homie = {} as Cat;
+```
+
+강제로 타입을 지정했기 때문에 타입 체커가 오류를 무시한 것입니다. 이러한 이유로 타입스크립트보다 타입 정보를 더 잘 알고 있는 상황에만 타입 단언문을 사용하는 것이 좋습니다.
+
+#### ➕ 화살표 함수의 반환 타입 선언
+
+화살표 함수의 타입 선언이 다소 까다롭기 때문에 따로 다뤄보겠습니다. 화살표 함수 안에서 타입과 함께 변수를 선언하는 것이 가장 직관적입니다.
+
+```
+const cats = ['cherie', 'homie', 'honey'].map(name=> {
+const cat:Cat = {name};
+return cat
+});
+```
+
+그러나 이 방식은 조금 번잡해보인다는 단점이 있습니다. 코드를 좀 더 간결하게 만들어보겠습니다.
+
+```
+const cats:Cat[] = ['cherie', 'homie', 'honey'].map(
+(name):Cat -> ({name})
+);
+```
+
+💥 **Boom!** 우리가 원하는 타입을 직접 명시하고, 타입스크립트가 할당문의 유효성을 검사하게 만들었습니다.
+
+### 💡 잉여 속성 체크의 한계 인지하기
+
+타입이 명시된 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 속성이 있는지, 그리고 '그 외의 속성은 없는지' 확인합니다. 이를 잉여 속성 체크라고 부르는데요, 잉여 속성 체크 역시 조건에 따라 동작하지 않는다는 한계가 있고, 일반적인 할당 가능 검사와 함께 쓰이면 구조적 타이핑이 무엇인지 혼란스러워질 수 있습니다. **잉여 속성 체크는 할당 가능 검사와는 별도의 과정이라는 것**을 기억하세요.
+
+잉여 속성 체크는 구조적 타이핑 시스템에서 허용되는 속성 이름의 오타 같은 실수를 잡는 데 효과적인 방법입니다. 하지만 적용 범위가 매우 제한적이며 오직 객체 리터럴에만 적용됩니다. 임시 변수를 도입하면 잉여 속성 체크를 건너뛸 수 있다는 점을 기억해야 합니다.
diff --git a/chapter2/ramgee/item6-8.md b/chapter2/ramgee/item6-8.md
index 436715d..b6c9572 100644
--- a/chapter2/ramgee/item6-8.md
+++ b/chapter2/ramgee/item6-8.md
@@ -1,3 +1,32 @@
-## 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
+# 아이템 6-8 (33p - 46p)
+## 아이템 6 - 편집기를 사용해 타입 시스템 탐색하기
+- 편집기에서 타입스크립트 언어 서비스를 적극활용하는 것이 좋다.
+- `Go to defintion`을 통해 타입 선언을 탐색해보는 것이 좋다.
----
+## 아이템 7 - 타입이 값들의 집합이라고 생각하기
+- `Never` 타입: 공집합
+- `Lireral` 타입 (`unit` 타입): 한 가지 값의 집합
+- `Union` 타입: 값의 합집합
+- `Intersection` 타입: 값의 교집합
+ - 타입 내의 속성을 모두 포함한 값
+ - Q. 그러면 Union이랑 뭐가 달라요..?
+ A. Union은 공통으로 가지는 속성
+- `Interface`: 타입 범주에 대해 약속을 정의할 수 있는 추상형식
+- `extends` vs `implements`
+ - `extends`: 클래스가 부모로부터 속성, 메서드를 상속하는 것.
+ - `implements`: 클래스가 속성, 메서드를 구현해야하는 것.
+- `Exclude` 키워드: 일부 타입을 제외할 수 있음.
+ - Q. 타입이 유효할 때만? 45p
+- `tuple`: 배열처럼 작동하는 타입스크립트 타입
+- `unknown`: 전체 집합
+
+## 아이템 8 - 타입 공간과 값 공간의 심벌 구분하기
+- [타입스크립트 플레이그라운드](https://www.typescriptlang.org/play/): 타입스크립트 소스로부터 변환된 자바스크립트 결과물을 보여줌
+- 모든 값은 타입을 가지지만 타입은 값을 가지지 않음.
+- class나 enum 키워드는 타입과 값 두 가지로 사용될 수 있음.
+ - enum? enumerated type
+- 키워드들은 공간과 값 공간에서 다른 목적으로 사용가능.
+ - class가 타입으로 쓰일 때는 형태가 사용되는 반면, 값으로 쓰일 때는 생성자가 사용.
+ - typeof가 타입으로 쓰일 때는 값을 읽어서 타입을 반환, 값으로 쓰일 때는 자바스크립트의 typeof 연산자로 사용.
+ - "foo" => 문자열 리터럴 or 문자열 리터럴 타입 -> 차이점 구별
+ - this가 타입으로 쓰일 때는 일명 다형성 this라고 불리는 this의 타입을 반환, 값으로 쓰일 때는 자바스크립트의 this.
diff --git a/chapter2/reyou/item01-14.md b/chapter2/reyou/item01-14.md
new file mode 100644
index 0000000..2b05ce0
--- /dev/null
+++ b/chapter2/reyou/item01-14.md
@@ -0,0 +1,155 @@
+## 아이템 01. TS 와 JS 관계 이해하기
+
+- JS 슈우퍼셋임
+- TS 라서 무서워하지말 것. JS에서 마이그레이션 할 수 있음.
+- 컴파일과정이 필요함 번거롭지만 뭐 어쩌겠으.
+- 타입을 추론한다는 `정적` 방식은 장점이 있음.
+ - 그것은 빌드나 컴파일전에 미리 오류나 문제점들을 알 수 있다는 것.
+ - 그래도 만능은 아님
+ - 인생은 엄격하게 살자
+
+## 아이템 02. TS 설정 이해하기
+
+- TS 컴파일러 설정 개 많음....
+ - 근데 나중에 찾음 됌 tsconfig.json
+- noImplicitAny : 이거 꼭 설정. 애니있는 타입스크립트는 타입스크립트가 아이다
+- srtictNullCheck : 널과 언디파인드를 막 할당하지말라 `-_-` 요거 설정해서 의도적 명시할 것.
+ - 아무튼 이들 설정은 짜기 힘들지만 고급진 품질코드를 위해 미리하는게 좋음.
+
+## 아이템 03. 코드생성과 타입이 관계없음
+- TS 컴파일러는
+1. 컴파일(트랜스파일 TS->JS)함
+2. 코드 타입 오류 체크해줌ㅋ
+ - 하지만 대충.. 컴파일하면 JS 튀어나오긴함
+- 런.타.임.엔 타.입.체.크. 불가 ㅠ(흠?)
+ - 아 뭐 대충 알 것같다...
+ - 인스턴스오브 체크는 런타임에...
+- 아무쪼록 태그된 유니온이란 기법이 있어서 요런건 좀 특이하구나... 하고 봄
+ - https://twitter.com/RE_U_CAT/status/1517866788394258432
+- 타입을 클래스로 만들면, 타입(런타임 접근불가)와 값(런타임 접근가능)을 둘다 쓰기도한다....
+ - 클래스로 만들래... 아 클래스 싫은뎅 -ㅅ-
+ - 인스턴스 오브 어쩌구는 아이탬8에서.
+- 타입연산은 런타임에 영향을 주지 않은다는 말은 타입체커를 우회할 수 있군아....
+ - https://twitter.com/RE_U_CAT/status/1517868440048238593
+ - 이거 보면 변환된 코드까지 보면 됨.
+ - 그럼 뭐.... 대충 다통과해서 곤란쓰
+- 런타임 타입은 선언된 타입과 다를 수 있데...?
+ - 이유는 뭘까.
+ - 흠... 런타임중에(API결과)가 확실히 맞을 수 않을 수 있구나. 불린으로 해서 불린이 온다는 보장이 없단소리군.
+- TS Type 함수를 오버로드 할 쑤 없슴댜
+ - 일반적인 오버로딩 기능은 지원함
+ - 근데 구현체만 남아 안될 수 있음.
+ - 하여튼 아이템 50에서 알아보자.
+ - https://twitter.com/RE_U_CAT/status/1517879363160920065
+
+- TS Type는 런타임 성능에 영향 없음.
+ - 대신 빌드타임 ^^ (심볼같은걸 다 뗀다.)
+
+## 아이템 04. 구조적 타이핑 익숙ㅋ
+- 덕타이핑이란~ 객체가 어떤 타입에 부합하는 변수와 메서드를 가질 경우, 객체를 해당 타입에 속하는 것으로 간주한다. (오리처럼 걷고, 헤엄치고, 짹짹이면? => 오리다)
+- 일단 타입을 정하고, 구조적으로 만드는데에 익숙해 져야겠네? 음... JS는 걍 짜면 되는데...
+- 그치만 구조적 타이핑에 문제도 있다.
+ - JS의 고질적인 0.1 + 0.2 = 0.30000000000000004 요런 문제들 것들! 이런건 체크 못한다.
+ - 포함관계에 (?이렇게 써도되나) 3D는 2D 개념을 포함하고 있으니까, 타입체크에서도 회피가능.... 문제가있다. 이런걸 오픈(*타입 확장에 열려있다.)되어있다고 하는구나 `-_-;;;`
+- 어.. 그래서 클래스 방식으로 (슈가 신덱싱) 짜도... 인스턴스가 예상과 다를 수 있다.
+ - 구조적으로 짰지만, 사용자가 생성자를 안타는 형태로 해서 타입을 회피하고 선언을 해버리면 원하지않은 결괄를 가져옴.
+ - [샘플을 만들었다-링크는 트이터로](https://twitter.com/RE_U_CAT/status/1517894759960150016)
+- 그치만 구조적 타이핑하면 유닛테스팅 쉽게 가능
+ - 이유는 디비에대한 추상화(SQL쿼리가 스트링이고 리턴이 애니라는걸 명시)가 되기에... 아무튼 이건 아이템 51에서 다시보자.
+
+## 아이템 05. Any 타입 쓰지마
+- 왜? 애니? ㅇㅇ... 근데 디비...리턴되는건 ^^
+- 아무튼 점진적이고 옵셔널한 타입이있다.
+ - 그치만 애니는 쓰지말라...
+ - 타입스크립트의 언어가 물러터지기 때문.
+ - 타입 왜씀?
+
+
+## 아이템 06. 편집기로 TS 써보기
+- TSC, TSSERVER 친구가 있다.
+- VSCODE쓰면 짱이다.
+- 아무튼 편집기 짱이니까, 그거 TS접목해서 돌아가도록 설정해서 써라...
+ - 쓰면, node 같은걸 Fetch 해 왔을 때, 편집기로 탐색이 가능하다. (==> 타입추론이 라이브러리도 가능하다는 의미. ==근데 d.ts파일이 있어야함ㅋㅋㅋㅋㅋㅋㅋ)
+ - https://joshua1988.github.io/ts/usage/declaration.html
+
+## 아이템 07. 타입값들이 집합이라고?
+- 이잉!? 집합이었구나. 나도 첨 알았다. 이런거다..
+- 엄격한 상속관계가 아니라, 겹치지는 집합으로 표현 된다. 서브타입이 아니면서도 겹쳐질 수 있음
+- 타입 선언 안해도 타입이 결정될 수 있음
+- 합집합이나 교집합에 대한 내용도 있으니 집합이라고 생각하면 편하다. 타입은 그래서 집합이다.
+- 네버(never)는 공집합 (얘는 루프문 탈때나 씀)
+- keyof 는 나중에 다시 볼 것
+
+## 아이템 08. 타입공간과 vs 값공간 씸벌 구분
+- 타입스크립트를 읽을 때, 타입인지, 값인지 플레이그라운드를 통해서 개념을 익혀라 ㅠㅠㅠㅠ
+- 타입은 값을 안가짐. 그래서 찍어도 안나오고 에러남
+ - interface {} 나, type{} 에만 존재함
+- 클래쓰나 이넘 같은 키워드는 헐..... 타입, 값 두가지 로 쓸 수 있다. 콘솔로 찍어보니 그릏다.
+- "ㅇㅅㅇ" -> 리터럴이나 타입일 수 있음. 구분은? 알아서 해야지뭐...
+- typeof, this 등등등... 이것들은 타입일 수도 있고 공간 값일 수 있다.
+- 결론은 타입과 값을 구분 잘하라는거고
+ - 매개변수에서도 잘 추론되니까 나눠 쓰라는건데 아이템 20에서 다시볼 내용.
+
+## 아이템 09. 타입 단언ㄴㄴ 타입선언ㅇㅋ
+- 타입 선언과 타입 단언은 둘 다 이건 이 타입이야! 한다지만, 타입 단언은 ㄴㄴ 선언 ㅇㅋ
+- 단언은 오류를 못잡아냄 그러니까 (: Type) 쓰라고
+- 화살표 함수의 반환타입도 명시하자
+ - 내부에서 아니면 직관적으로 선언하거나
+ - 타입에 확 정의할 것.
+- 내가 TS보다 타입을 더 잘알 때만 단언하거나 null 쓸 것
+- dom 타입은 55 아이템에서
+- 접미사 ! 는 타입단언
+- unknown은 모든 타입의 서브타입. 하지만 뭔가 위험한짓을 하고 있겠지?
+
+## 아이템 10. 객체 래퍼타입 피하자
+- 래퍼타입 이해하기
+ - 직접사용, 인스턴스 작성 피하기
+ - 객체 래퍼타입은 잘 쓰지말고, 기본형 타입을 쓸 것.
+ - String 보다 string
+ - Number 보다는 number 같은걸로!!!!!
+
+- 기본형 말고 기본형을 잘 쓰도록 말아둔 래퍼타입이란 전설적인 객체 타입 친구들이 있다.
+- 몽키패치란? 원숭이 장난처럼 중간에 도는 코드에 슉샥 코드로 수정을 가하는 것
+ - 이런식으로 수정을 하면 원래 동작하는
+ "문자문자".charAt 를
+ String.prototype.charAt 로 재 선언해서 해당 위치의 this를 강제바인딩, 결과를 다르게 만들 수 있다.
+- TS는 기본형과 객체타입레퍼를 따로 구분해 모델링
+
+## 아이템 11. 잉여속성체크한계인지
+- 와 ... 잉여속성 체크 한계가 뭐야??????
+ - 남는 속성이나 추가한 속성 같은걸 말한거구나.
+- 객체리터럴을 변수에 할당, 함수에 매개변수로 전달할 때, 잉여속성 체크 수행.
+ - 오류찾는 효과적인 방법
+ - TS체커가 수행하는 일반적 구조적 할당과, 가능성 체크는 역할이 다름.
+- 잉여속성 체크엔 한계가 있음. 임시변수를 도입하면 건너뛸 순 있는데...
+ - https://twitter.com/RE_U_CAT/status/1518135139993530368
+
+
+## 아이템 12. 함수 표현식에 타입 적용
+- 아 당연히 선언식과 표현식은 다르지
+ - TS에선 표현식 쓰는게 좋음. 매개변수부터 반환값까지 전체를 함수타입으로 선언하여 재사용 가능한 장점.
+- 매개변수나 반환값에 타입을 명시보다, 함수표현식 전체에 타입구조를 매핑하는게 좋다.
+ - 이왕이면 하나로 통합하는것도 좋아.
+- 같은타입 타입 시그니처를 반복적으로 작성된다면 타입을 분리하거나 이미 존재하는 타입이 없나볼 것. 라이브러리를 직접 만들면 공통 콜백을 만들면 좋음.
+- 다른함수나 시그니처를 참고하려면 typeof fn을 쓴다.
+
+## 아이템 13. 타입 vs 인터페이스
+- 타입과 인터페이스의 차이점과 비슷한점을 이해해야지
+ - 인터페이스 - 타입확장 가능
+ - 타입 - 인터페이스를 확장 가능
+ - 유니온 타입은 있지만
+ - 유니온 인터페이스는 없음.
+- 한타입을 타입과 인터페이스로 작성할 줄 알아야지
+- 프로젝트에서 어떤걸 할지 결정하고 일관되게 짜야지. 리액트에서 컴포넌트는 타입으로 선언하고 메서드는 인터페이스로 만든다던가
+- 오.. 선언병합이란게 인터페이스에 있구나. 나중에 많이 씀.
+
+## 아이템 14. 타입 연산과 제너릭 사용으로 반복줄이기
+- 제너릭 친구를 써서 반복 줄이기다. (DRY)
+- 타입에 이름을 붙여 반복 피하기, Extends 사용해서 인터페이스 반복 피하기.
+ - 열심히 반복 줄이기 ...
+
+- 타입간 매핑을 공부하면 좋음... keyof, typeof, 인덱싱, 매핑된 타입 등...
+ - 매핑된 타입은 (k in keyof Options) 같은건 순회하면서 Options 내에 k 속성이 있는지 찾는다. (Partial 참조)
+ - `80쪽좀 나중에 다시 보자.`
+- 제너릭은 타입을 위한 함수 타입을 반복하는 대신, 제너릭으로 타입간에 매핑가능
+- 표준라이브러리에 정의된 Pick, Partial, ReturnType 같은 제너릭타입에 익숙하져야.....
diff --git a/chapter2/reyou/item15-18.md b/chapter2/reyou/item15-18.md
new file mode 100644
index 0000000..1577a45
--- /dev/null
+++ b/chapter2/reyou/item15-18.md
@@ -0,0 +1,38 @@
+## 아이템 15. 동적 데이터에 인덱스 시그니처 사용하기
+
+- 런타임 때 까지 객체속성을 알 수 없는 경우에만 인덱스 시그니처 쓰기.
+ - 인덱스 시그니쳐가 뭐야
+https://developer-talk.tistory.com/297
+ - 인덱스 형태로 쿠쿠루삥뽕하게 만들어 주는 것
+- 인덱스 시그니처타입엔 undefined 를 써서 안전함을 고려 할 것.
+- 가능하면 인터페이스, Record, 매핑된 타입 같은걸로 인덱스 시그니쳐 쓰지말고 명확하게 ㅠㅠ
+- 자동완성도 안되니 고심할 것.
+- 데이터를 동적으로 표현할 때 사용.
+
+
+## 아이템 16. Number 인덱스 시그니처보다 Array, 튜플, ArrayLike를 사용하기
+
+- 배열은 객체이므로 키는 숫자가 아니라 문자열, 인덱스 시그니쳐로 사용 된 number 타입은 버그잡을 순수 타입 스크립트
+- (제목과 동일)
+-
+
+## 아이템 17. 변경 관련된 오류 인지를 위해 readonly 쓰기
+- 아이고 당연히 한번 딱 박으려고 했는데, 바뀌면 안되죠 readonly로 선언하자.
+- JS는 배열 변경이 가능하기 때문에, TS에서도 오류없이 넘어가기도 하는데, 이 때 오류를 좁힐 readonly가 필요하다.
+ - 딱 보면 읽기전용. 한번 만들면 변경불가
+- readonly의 경우 호출하는 함수에도 넣을 수 있다.
+ - ```function arrSum(arr: readonly number[]){}``` 이런식으로.
+ -
+
+- 변경하면서 발생하는 오류도 잡고, 변경이 발생하는 코드도 쉽게 찾을 수 있다.
+- const 와 readonly는 다른 것.
+ - 얕게 동작한다. 잘 알아둘 것.
+
+## 아이템 18. 매핑된 타입 사용. 값동기화
+- 매핑된 타입을 사용해서 관련된 값과 타입 맞출 것.
+ - 데이터가 변하면, 리렌더링 할 수 있지.
+ - 핸들러가 변하면, 리렌더링 필 요 없지.
+- 104page 부터 보면 된다.
+ - https://t.co/USm0A7KcXy
+- 인터페이스에 속성을 추가할 때, 선택을 강제하도록 매핑된 타입을 고려할 것....
+ - 실패에 대한 방법을 고민해서 예외처리를 하는것도 중요하다... 어떤 식으로 판단을 할지.
\ No newline at end of file
diff --git a/chapter2/teasan/item6-8.md b/chapter2/teasan/item6-8.md
index 436715d..3dd5b18 100644
--- a/chapter2/teasan/item6-8.md
+++ b/chapter2/teasan/item6-8.md
@@ -1,3 +1,57 @@
## 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
----
+- 타입스크립트의 가장 중요한 역할은 '타입 시스템'에 있다.
+- 타입스크립트를 설치하면 두 가지를 실행할 수 있게 된다.
+ - 타입스크립트 컴파일러(tsc)
+ - 타입스크립트 서버(tsserver)
+- 보통은 타입스크립트 컴파일러를 실행하는 것이 주된 목적이나, 타입스크립트 서버 또한 '언어 서비스'를 제공한다는 점에서 중요하다.
+- 타입스크립트 서버에서 제공하는 '언어 서비스'는 코드의 자동 완성, 명세(사양) 검사, 검색, 리팩터링이 포함된다. 그리고 보통 편집기 를 통해서 '언어 서비스'를 이용하며, 타입스크립트 서버에서 '언어 서비스'를 제공하도록 설정하는 것이 좋다. '자동 완성 서비스'를 이용하면, 타입스크립트 코드 작성이 간편해지며, 편집기를 사용함으로써 타입스크립트의 타입 추론과 그 실행 시점에 대한 개념을 학습할 수 있게 된다.
+
+
+
+## 아이템 7. 타입이 값들의 집합이라고 생각하기
+
+- '할당 가능한 값들의 집합'은 타입이다. 또한 이 집합은 타입의 '범위'라고 부르기도 한다.
+- 구조적 타이핑 규칙들은 어떠한 값이 다른 속성도 가질 수 있음을 의미한다. 또한 함수 호출의 매개변수에서도 다른 속성을 가질 수 있다.
+- 타입 연산자는 인터페이스의 속성이 아닌, 값의 집합(타입의 범위)에 적용된다. 추가적인 속성을 가지는 값도 여전히 그 타입에 속한다.
+- 타입의 집합이라는 관점에서 `extends`의 의미는 "~의 부분 집합` 이라는 의미로 받아들일 수 있다.
+- 'A는 B를 상속', 'A는 B에 할당 가능', 'A는 B의 서브타입'이란 말들은 모두 'A는 B의 부분 집합' 이라는 말과 같은 의미이다.
+
+
+
+## 아이템 8. 타입 공간과 값 공간의 심벌 구분하기
+
+- 타입스크립트 코드에서는 '타입'과 '값'을 구분하여 읽어야 한다.
+- 모든 값은 '타입'을 가진다. 그러나, 타입은 '값'을 가지지 않는다.
+- 값으로 쓰이는 `this`는 자바스크립트의 `this` 키워드이다.
+- 타입으로 쓰이는 `this`는 '다형성 this'라고 불리는 `this`의 타입스크립트 타입이다.
+
+
+
+## 스터디 정리
+
+- `type` 은 값들의 타입을 넣을 때 사용.
+- `interface` 는 객체 타입에서만 사용, 주로 객체의 역할을 부여할 때 사용.
+
+### `enum` 대신 `union` 타입을 쓰는 이유
+
+> `enum` 은 enumerated type(열거형)을 의미.
+
+```js
+type Vote = -1 | 0 | 1;
+
+function voting(vote: number) {
+ console.log(vote);
+}
+
+voting(3); // 정상적으로 동작
+```
+
+```js
+type Vote = -1 | 0 | 1;
+function voting(vote: Vote) {
+ console.log(vote);
+}
+
+voting(3); // type error!!
+```
diff --git a/chapter2/yell/item12-14.md b/chapter2/yell/item12-14.md
new file mode 100644
index 0000000..1cdc2b1
--- /dev/null
+++ b/chapter2/yell/item12-14.md
@@ -0,0 +1,299 @@
+## 아이템 12. 함수 표현식에 타입 적용하기
+
+```ts
+function rollDice1(sides: number): number {
+ /* ...*/
+} // 문장
+const rollDice2 = function (sides: number): number {
+ /* ... */
+}; // 표현식
+const rollDice3 = (sides: number): number => {
+ /* ... */
+}; // 표현식
+```
+
+- 타입스크립트에서는 함수 표현식을 사용하는 것이 좋다. 함수의 매개변수부터 반환값까지 전체를 함수 타입으로 선언하여 **함수 표현식에 재사용할 수 있다**는 장점이 있다.
+
+```ts
+type DiceRollFn = (sides: number) => number;
+const rollDice: DiceRollFn = (sides) => {
+ /* ... */
+};
+```
+
+### 함수 타입의 선언
+
+- 함수 타입의 선언은 불필요한 코드의 반복을 줄인다.
+
+```ts
+function add(a: number, b: number) {
+ return a + b;
+}
+function sub(a: number, b: number) {
+ return a - b;
+}
+function mul(a: number, b: number) {
+ return a * b;
+}
+function div(a: number, b: number) {
+ return a / b;
+}
+
+// 반복되는 함수 시그니처를 함수 타입으로 통합
+type BinaryFn = (a: number, b: number) => number;
+
+const add: BinaryFn = (a, b) => a + b;
+const sub: BinaryFn = (a, b) => a - b;
+const mul: BinaryFn = (a, b) => a * b;
+const div: BinaryFn = (a, b) => a / b;
+```
+
+
+
+- 시그니처가 일치하는 다른 함수가 있을 때도 함수 표현식에 타입을 적용
+
+```ts
+declare function fetch(
+ input: RequestInfo,
+ init?: RequestInit
+): Promise;
+
+const checkedFetch: typeof fetch = async (input, init) => {
+ const response = await fetch(input, init);
+ if (!response.ok) {
+ throw new Error("Request failed: " + response.status);
+ }
+ return response;
+};
+// checkedFetch의 반환 타입을 보장하며, fetch와 동일
+```
+
+- 함수의 매개변수에 타입 선언을 하는 것보다 함수 표현식 전체 타입을 정의하는 것이 코드도 간결하고 안전하다.
+
+
+
+> 처음에 자바스크립트 강의를 들을 때 강사분이 함수를 사용할 때 함수표현식 `const add = function () {}`을 사용해서 이렇게 썼는데 최근에는 화살표 함수도 많이 쓰는 편이고 팀에서 쓰는 컨벤션에 맞춰 쓰는 게 가장 베스트라고 생각한다.
+
+
+
+
+## 아이템 13. 타입과 인터페이스의 차이점 알기
+
+대부분의 경우에는 타입을 사용해도 되고 인터페이스를 사용해도 된다. 그러나 타입과 인터페이스 사이에 존재하는 차이를 분명하게 알고, 같은 상황에서는 동일한 방법으로 명명된 타입을 정의해 일관성을 유지해야 한다.
+
+
+
+### 인터페이스 선언과 타입 선언의 비슷한 점
+
+- 명명된 타입은 인터페이스로 정의하든 타입으로 정의하든 상태에는 차이가 없다.
+
+```ts
+type TState = {
+ name: string;
+ capital: string;
+};
+
+interface IState {
+ name: string;
+ capital: string;
+}
+
+const wyoming: TState = {
+ name: "Wyoming",
+ capital: "Cheyenne",
+ population: 500_000, // 에러발생, 해당 형식은 TState 형식에 할당할 수 없습니다.
+};
+```
+
+`wyoming`에 `TState`를 사용하든, `IState`를 사용하든 위와 같은 에러가 발생한다.
+
+- 인덱스 시그니처와 함수 타입은 인터페이스와 타입에서 모두 사용할 수 있다.
+
+```ts
+type TDict = { [key: string]: string };
+interface IDict {
+ [key: string]: string;
+}
+
+type TFn = (x: number) => string;
+interface IFn {
+ (x: number): string;
+}
+```
+
+- 인터페이스는 타입을 확장할 수 있으며, 타입은 인터페이스를 확장할 수 있다.
+
+```ts
+interface IStateWithPop extends TState {
+ population: number;
+}
+type TStateWithPop = IState & { population: number };
+
+// IStateWithPop과 TStateWithPop은 동일하다
+```
+
+
+
+### 인터페이스와 타입의 다른 점
+
+- 인터페이스는 타입을 확장 할 수 있지만, 유니온은 할 수 없으며, `type`키워드는 일반적으로 `interface`보다 쓰임새가 많다.
+
+```ts
+type Input = {
+ /*...*/
+};
+type Ouput = {
+ /*...*/
+};
+interface VariableMap {
+ [name: string]: Input | Ouput;
+}
+
+type NameVariable = (Input | Ouput) & { name: string };
+```
+
+`NameVariable`이 `name`속성을 뒤에 붙인 것처럼 인터페이스인 `VariableMap`은 다음과 같이 표현할 수 없다.
+
+
+
+- 타입에는 없는 인터페이스의 몇 가지 기능
+
+ - **보강**(argument)
+
+ ```ts
+ interface IState {
+ name: string;
+ capital: string;
+ }
+
+ interface IState {
+ population: number;
+ }
+
+ const wyoming: IState = {
+ name: "Wyoming",
+ capital: "Cheyenne",
+ population: 500_000,
+ }; // 정상
+ ```
+
+ 같은 인터페이스명을 사용해서 보강을 하는데 예제처럼 속성을 확장하는 것을 **선언 병합**(declaration merging)이라고 한다.
+
+
+
+### 그래서 타입과 인터페이스 중 어느 것을 사용해야 할까?
+
+- 타입과 인터페이스의 차이점과 비슷한 점을 이해하고 두 가지 문법을 사용해서 작성하는 방법을 터득해야 한다.
+- 프로제그에서 어떤 문법을 사용할지 결정할 때 한 가지 일관된 스타일을 확립하고, 보강 기법이 필요한지 고려해야 한다.
+
+
+
+
+## 아이템 14. 타입 연산과 제너릭 사용으로 반복 줄이기
+
+같은 코드를 반복하지 말라는 **DRY**(Don't Repeat Yourself)의 원칙을 타입에도 적용해야 한다.
+
+```ts
+function distance(a: { x: number; y: number }, b: { x: number; y: number }) {
+ /*...*/
+}
+// 매개변수가 반복되는 함수를 아래와 같이 정리
+
+interface Point2D {
+ x: number;
+ y: number;
+}
+function distance(a: Point2D, b: Point2D) {
+ /*...*/
+}
+
+// 시그니처로 명명된 타입을 분리
+type HTTPFunction = (url: string, opts: Options) => Promise;
+const get: HTTPFunction = (url, opts) => {
+ /*...*/
+};
+const post: HTTPFunction = (url, opts) => {
+ /*...*/
+};
+
+// 한 인터페이스가 다른 인터페이스를 확장하게 해서 반복 제거
+interface Person {
+ firstName: string;
+ lastName: string;
+}
+
+interface PersonWithBirthDate extends Person {
+ birth: Date;
+}
+```
+
+
+
+### 인덱싱하여 속성의 타입에서 중복 제거
+
+```ts
+interface State {
+ userId: string;
+ pageTitle: string;
+ recentFiles: string[];
+ pageContents: string;
+}
+
+interface TopNavState {
+ userId: string;
+ pageTitle: string;
+ recentFiles: string[];
+}
+
+type TopNavState = {
+ [k in "userId" | "pageTitle" | "recentFiles"]: State[k];
+};
+```
+
+
+
+### `keyof`, `typeof`
+
+- `keyof`는 타입을 받아서 속성 타입의 유니온을 반환한다.
+
+```ts
+interface Options {
+ width: number;
+ height: number;
+ color: string;
+ label: string;
+}
+
+type OptionsUpdate = { [k in keyof Options]?: Options[k] };
+type OptionKeys = keyof Options;
+// 타입이 "width" | "height" | "color" | "label"
+```
+
+- `typeof`
+
+```ts
+const INIT_OPTIONS = {
+ width: 640,
+ height: 480,
+ color: "#00FF00",
+ label: "VGA",
+};
+
+type Options = typeof INIT_OPTIONS;
+```
+
+
+
+### 제네릭타입
+
+제네릭 타입은 타입을 위한 함수와 같다. 그리고 함수는 코드에 대한 DRY 원칙을 지킬 때 유용하게 사용된다.
+
+- `extends` 제네릭 타입의 매개변수를 제한하기 위한 키워드
+
+```ts
+type Pick = {
+ [k in K]: T[k]
+};
+```
+
+타입이 값의 집합이라는 관점에서 생각하면 `extends`는 '확장'이 아니라 '부분 집합'이라는 개념으로 이해할 것.
diff --git a/chapter2/yell/item15-18.md b/chapter2/yell/item15-18.md
new file mode 100644
index 0000000..96f387d
--- /dev/null
+++ b/chapter2/yell/item15-18.md
@@ -0,0 +1,397 @@
+## 아이템 15. 동적 데이터에 인덱스 시그니처 사용하기
+
+타입스크립트에서는 타입에 **인덱스 시그니처**를 명시하여 유연하게 매핑을 표현할 수 있다.
+
+```tsx
+type Rocket = { [property: string]: string };
+const rocket: Rocket = {
+ name: "Falcon 9",
+ variant: "v1.0",
+ thrust: "4,940 kN",
+};
+```
+
+`[property: string]: string`이 인덱스 시그니처이며, 다음 세 가지 의미를 담고 있다.
+
+- 키의 이름: 키의 위치만 표시하는 용도
+- 키의 타입: `string`이나 `number` 또는 `symbol`의 조합이어야 하지만, 보통은 `string`을 사용
+- 값의 타입: 어떤 것이든 될 수 있다. `string`이기만 하면 뭐든 괜찮다는 의미로 쓰인건가
+
+
+
+이렇게 인덱스 시그니처를 썼을 때 타입 체크가 수행되면 네 가지 단점이 드러난다.
+
+- 잘못된 키를 포함해 모든 키를 허용
+
+```tsx
+const rocket1: Rocket = { name: "Falcon 9" }; // 정상
+const rocket2: Rocket = { Name: "Apollo" }; // 정상
+```
+
+- 특정 키가 필요하지 않는다. `const rocket: Rocket = { }` 도 정상
+- 키마다 다른 타입을 가질 수 없다.
+
+```tsx
+const rocket: Rocket = {
+ name: 'Falcon 9',
+ variant: 'v1.0',
+ thrust: 4,940 // 에러, number여야 할 수도 있는데 무조건 string을 써야함
+}
+```
+
+- 타입스크립트 언어 서비스 중 하나인 자동 완성 기능이 동작하지 않는다.
+
+
+
+그러므로 이럴 경우에는 인덱스 시그니처를 쓰기보다는 `interface`를 쓸 수도 있다.
+
+```tsx
+interface Rocket {
+ name: string;
+ variant: string;
+ thrust_kN: number;
+}
+const falconHeavy: Rocket = {
+ name: "Falcon 9",
+ variant: "v1",
+ thrust_kN: 15_200,
+};
+```
+
+`interface Rocket`의 `thrust_kN`은 `number` 타입이며, 이제 타입스크립트에서 제공하는 언어 서비스인 자동완성, 정의로 이동, 이름 바꾸기 등이 모두 동작한다.
+
+
+
+- 인덱스 시그니처는 동적 데이터를 표현할 때 사용한다. 런타임 때까지 객체의 속성을 알 수 없을 경우에만, 예를 들어 CSV 파일처럼 헤더 행에 열 이름이 있고, 데이터 행을 열 이름과 값으로 매핑하는 객체로 나타내고 싶은 경우
+
+```tsx
+function parseCSV(input: string): { [columnName: string]: string }[] {
+ const lines = input.split("\n");
+ const [header, ...rows] = lines;
+ const headerColumns = header.split(",");
+
+ return rows.map((rowStr) => {
+ const row: { [columnName: string]: string } = {}; // 열 이름이 무엇인지 모르기 때문에 인덱스 시그니처 사용
+ rowStr.split(",").forEach((cell, i) => {
+ row[headerColumns[i]] = cell;
+ });
+ return row;
+ });
+}
+```
+
+- 어떤 타입에 가능한 필드가 제한되어 있는 경우라면 인덱스 시그니처보다는 **선택적 필드** 또는 **유니온 타입으로 모델링**
+
+```tsx
+interface Row1 {
+ [column: string]: string;
+} // 너무 광범위
+interface Row2 {
+ a: number;
+ b?: number;
+ c?: number;
+ d?: number;
+}
+type Row3 =
+ | { a: number }
+ | { a: number; b: number }
+ | { a: number; b: number; c: number }
+ | { a: number; b: number; c: number; d: number }; // 가장 정확하지만 사용하기 번거로움
+```
+
+위와 같이 `string` 타입이 너무 광범위해서 인덱스 시그니처를 사용하는데 문제가 있다면, 제너릭타입 중 `Record` 을 사용하거나 매핑된 타입을 사용할 수 있다.
+
+
+
+### `Record` 사용하기
+
+```tsx
+// Type Vec3D = {
+// x: number;
+// y: number;
+// z: number;
+// }
+
+type Vec3D = Record<"x" | "y" | "z", number>;
+```
+
+
+
+### 매핑된 타입 사용하기
+
+```tsx
+type Vec3D = { [k in "x" | "y" | "z"]: number };
+type ABC = { [k in "a" | "b" | "c"]: k extends "b" ? string : number };
+
+const letter: ABC = {
+ a: 1,
+ b: "abc",
+ c: 3,
+};
+// 키 'b' 이외에는 다른 키의 경우 값이 number이다.
+```
+
+가능하다면 `interface`, `Record`, **매핑된 타입** 같은 인덱스 시그니처보다 정확한 타입을 사용하는 것이 좋다.
+
+
+
+
+---
+
+
+
+
+## 아이템 16. number 인덱스 시그니처보다는 Array, 튜플, ArrayLike를 사용하기
+
+- 배열은 객체이므로 키는 숫자가 아니라 문자열. 인덱스 시그니처로 사용된 타입은 버그를 잡기 위한 순수 타입스크립트 코드이다.
+- 인덱스 시그니처에 `number`를 사용하기보다는 `Array`나 튜플, 또는 `ArrayLike` 타입을 사용하는 것이 좋다.
+
+
+
+
+---
+
+
+
+
+## 아이템 17. 변경 관련된 오류 방지를 위해 readonly 사용하기
+
+- 삼각수를 출력하는 함수
+
+```tsx
+function printTriangles(n: number) {
+ const nums = [];
+ for (let i = 0; i < n; i++) {
+ nums.push(i);
+ console.log(arraySum(nums));
+ }
+}
+
+// 숫자의 합이 아닌 0부터 5까지 하나씩 출력되는 문제발생
+// arraySum이 nums를 변경하지 않는다고 간주해서 문제가 발생했다.
+```
+
+
+
+- `arraySum`이 배열을 변경하지 않는다는 선언해서 원하는대로 함수 구현
+
+```tsx
+function arraySum(arr: readonly number[]) {
+ let sum = 0;
+ for (const num of arr) {
+ sum += num;
+ }
+ return sum;
+}
+
+> printTriangles(5)
+// 0, 1, 3, 6, 10 출력
+```
+
+만약 함수가 매개변수를 수정하지 않는다면 `readonly`로 선언하는 것이 좋다. `readonly` 매개변수는 인터페이스를 명확하게 하며, 매개변수가 변경되는 것을 방지한다.
+
+
+
+### `readonly number[]`가 `number[]`와 구분되는 특징
+
+- 배열의 요소를 읽을 수 있지만, 쓸 수는 없다.
+- `length`를 읽을 수 있지만, 바꿀 수 없다.
+- 배열을 **변경**하는 `pop`과 같은 메서드를 호출할 수 없다.
+- `number[]`는 `readonly number[]`보다 기능이 많기 때문에, `readonly number[]`의 서브타입
+
+```tsx
+const a: number[] = [1, 2, 3];
+const b: readonly number[] = a;
+const c: number[] = b; // 에러 발생
+
+// 'readonly number[]' 타입은 'readonly'이므로
+// 변경 가능한 'number[]' 타입에 할당될 수 없습니다.
+```
+
+`readonly`를 사용하면 지역 변수와 관련된 모든 종류의 변경 오류를 방지할 수 있다.
+
+```tsx
+function parseTaggedText(lines: string[]): string[][] {
+ const paragraphs: string[][] = [];
+ const currPara: string[] = [];
+
+ const addParagraph = () => {
+ if (currPara.length) {
+ paragraphs.push(currPara);
+ currPara.length = 0; // 배열을 비움
+ }
+ };
+
+ for (const line of lines) {
+ if (!line) {
+ addParagraph();
+ } else {
+ currPara.push(line);
+ }
+ addParagraph();
+ return paragraphs;
+};
+
+// [ [], [], [] ]
+// 원치않는 방향으로 출력이 된다.
+```
+
+```tsx
+paragraphs.push(currPara);
+currPara.length = 0; // 배열을 비움
+```
+
+이 코드가 문제의 핵심인데, 새 단락을 `paragraphs`에 삽입하고 바로 지워 버린다. `currPara.length`를 수정하고 `currPara.push`를 호출하면 둘 다 `currPara` 배열을 **변경**한다. 그래서 `currPara`를 `readonly`로 선언하여 이런 동작을 방지할 수 있다.
+
+
+
+- 위 코드가 원하는대로 동작하도록 수정하는 건 세 가지 방법이 있다.
+
+```tsx
+function parseTaggedText(lines: string[]): string[][] {
+ const paragraphs: string[][] = [];
+ // 두번째, const paragraphs : (readonly string[])[] = [];
+ // 변경 가능한 배열의 readonly 배열
+ let currPara: string[] = [];
+
+ const addParagraph = () => {
+ if (currPara.length) {
+ paragraphs.push(currPara);
+ // 첫번째 복사본 만들기 paragraphs.push([...currPara]);
+
+ // 세번째, readonly 속성을 제거하기 위해
+ // 단언문 쓰기 paragraphs.push(currPara as string[])
+ currPara = [];
+ }
+ };
+
+ for (const line of lines) {
+ if (!line) {
+ addParagraph();
+ } else {
+ currPara = currPara.concat([line]);
+ }
+ addParagraph();
+ return paragraphs;
+};
+```
+
+
+
+얕게 동작하는 `readonly` , `Readonly` 제네릭에도 해당
+
+```tsx
+interface Outer {
+ inner: {
+ x: number;
+ };
+}
+
+const o: Readonly = { inner: { x: 0 } };
+o.inner = { x: 1 }; // 에러발생
+o.inner.x = 1; // 정상
+
+type T = Readonly;
+// type T = {
+// readonly inner: {
+// x: number;
+// };
+// }
+```
+
+`readonly` 접근제어자는 `inner`에 적용되는 것이지 `x`는 해당되지 않는다. 깊은 readonly 타입이 기본으로 지원되지 않지만, **제너릭을 만들거나** `ts-essentials`에 있는 `DeepReadonly` 제너릭을 사용하면 가능하다.
+
+
+
+### 인덱스 시그니처에서 사용하는 `readonly`
+
+```tsx
+let obj: { readonly [k: string]: number } = {};
+// Readonly<{[k: string]: number}
+
+obj.hi = 45; // 에러발생, 읽기만 허용 가능
+
+obj = { ...obj, hi: 12 }; // 정상
+obj = { ...obj, bye: 34 }; // 정상
+```
+
+인덱스 시그니처에 `readonly`를 사용하면 객체의 속성이 변경되는 것을 방지할 수 있다.
+
+
+
+
+---
+
+
+
+
+## 아이템 18. 매핑된 타입을 사용하여 값을 동기화하기
+
+- 타입 체커가 동작하도록 매핑된 타입과 객체 사용
+
+```tsx
+interface ScatterProps {
+ // The data
+ xs: number[];
+ ys: number[];
+
+ // Display
+ xRange: [number, number];
+ yRange: [number, number];
+ color: string;
+
+ // Events
+ onClick: (x: number, y: number, index: number) => void;
+}
+
+const REQUIRES_UPDATE: { [k in keyof ScatterProps]: boolean } = {
+ xs: true,
+ ys: true,
+ xRange: true,
+ yRange: true,
+ color: true,
+ onClick: false,
+};
+
+function shouldUpdate(oldProps: ScatterProps, newProps: ScatterProps) {
+ let k: keyof ScatterProps;
+ for (k in oldProps) {
+ if (oldProps[k] !== newProps[k] && REQUIRES_UPDATE) {
+ return true;
+ }
+ }
+ return false;
+}
+```
+
+`[k in keyof ScatterProps]`는 타입 체커에게 `REQUIRES_UPDATE`가 `ScatterProps`와 같은 키 값을 가져야 한다는 정보를 제공한다. 나중에 `ScatterProps`에 새로운 속성을 추가한 경우 `REQUIRES_UPDATE`도 동일한 키를 값을 가지지 않으면 타입에러가 발생한다.
+
+```tsx
+interface ScatterProps {
+ // ...
+ onDoubleClick: () => void;
+}
+
+const REQUIRES_UPDATE: { [k in keyof ScatterProps]: boolean } = {
+ // 에러 발생, 'onDoubleClick' 속성이 없습니다.
+};
+```
+
+
+
+- boolean 값을 가진 객체 대신 배열을 사용했다면
+
+```tsx
+const PROPS_REQUIRES_UPDATE: (keyof ScatterProps)[] = [
+ "xs",
+ "ys",
+ "xRange",
+ "yRange",
+ "color",
+ "onClick",
+];
+
+// ScatterProps에 없는 'onChange'와 같은 값을 넣으면 타입에러
+```
+
+**매핑된 타입**은 한 객체가 또 다른 객제와 정확히 같은 속성을 가지게 할 때 이상적이다. **인터페이스에 새로운 속성을 추가할 때, 선택을 강제하도록 매핑된 타입을 사용할 것인지 고려**해야 한다.
diff --git a/chapter2/yell/item6-8.md b/chapter2/yell/item6-8.md
index 436715d..d90ef9c 100644
--- a/chapter2/yell/item6-8.md
+++ b/chapter2/yell/item6-8.md
@@ -1,3 +1,44 @@
## 아이템 6. 편집기를 사용하여 타입 시스템 탐색하기
+- 타입스크립트를 설치하면, 컴파일러 `tsc`와 단독으로 실행할 수 있는 타입스크립트 서버 `tsserver`를 실행할 수 있다.
+
+- VS Code와 같은 편집기를 사용해 타입스크립트의 언어서비스를 사용할 수 있는데, 이 언어서비스에는 코드 자동 완성, 명세 검사, 검색, 리팩터링이 포함된다.
+
+- 타입스크립트 언어 서비스는 편집기에서 모델링된 타입 선언 파일을 볼 수 있다.
+
+
+
+---
+
+
+
+## 아이템 7. 타입이 값들의 집합이라고 생각하기
+
+- 타입은 ‘할당 가능한 값들의 집합'이라고 생각하면 된다. 여기서 집합은 타입의 범위.
+
+- 타입스크립트의 타입은 겹쳐지는 집합(벤 다이어그램)으로 표현된다.
+
+ | **타입** | **집합 개념** |
+ | --------- | ----------------------------------------- |
+ | never | 아무 값도 포함하지 않는 공집합 |
+ | literal | 한 가지 값만 포함 |
+ | union | 두 개 혹은 세 개의 값을 포함, 합집합 |
+ | interface | 범위가 무한대, 타입 범위 내의 값들의 집합 |
+ | unknown | 전체 집합 |
+
+
+
---
+
+
+
+## 아이템 8. 타입 공간과 값 공간의 심벌 구분하기
+
+- 모든 값은 타입을 가지지만, 타입은 값을 가지지 않는다.
+- `class`나 `enum` 같은 키워드는 타입과 값 두 가지로 사용될 수 있다.
+- `typeof`, `this` 그리고 많은 다른 연산자들(`&`, `|`)과 키워드들(`extends`, `in`)은 타입 공간과 값 공간에서 다른 목적으로 사용될 수 있다.
+
+ | **타입** | **값** |
+ | ---------------------------------------- | --------------------------- |
+ | 심벌 앞에 `type`이나 `interface` | 심벌 앞에 `const`이나 `let` |
+ | 심벌 뒤에 타입 선언 `:` 또는 단언문 `as` | 심벌 뒤에 `=` |
diff --git a/chapter2/yell/item9-11.md b/chapter2/yell/item9-11.md
new file mode 100644
index 0000000..32fb177
--- /dev/null
+++ b/chapter2/yell/item9-11.md
@@ -0,0 +1,193 @@
+## 아이템 9. 타입 단언보다는 타입 선언을 사용하기
+
+```ts
+interface Person {
+ name: string;
+}
+
+const alice: Person = { name: "Alice" }; // 타입은 Person
+const bob = { name: "Bob" } as Person; // 타입은 Person
+```
+
+이 두 가지 방법은 결과가 같아 보이지만 그렇지 않다.
+
+- 첫 번째 `alice: Person`은 변수에 **타입 선언**을 붙여서 그 값이 선언된 타입임을 명시
+- 두 번째 `as Person`은 **타입 단언**을 수행
+
+
+
+### 타입 단언보다 타입 선언을 사용하는 게 나은 이유
+
+```ts
+const alice: Person = {}; // 오류 발생, 'Person' 유형에 필요한 'name' 속성이 '{}'유형에 없습니다.
+const bob = {} as Person; // 오류 없음
+```
+
+타입 선언은 할당되는 값이 해당 인터페이스를 만족하는지 검사한다. 첫 번째 예제에서는 그러지 못했기 때문에 타입스크립트가 오류를 표시하고, 타입 단언은 강제로 타입을 지정했으니 타입 체커에게 오류를 무시하라고 하는 것
+
+- **타입 단언**이 꼭 필요한 경우가 아니라면, 안전성 체크도 되는 **타입 선언**을 사용하는 것이 좋다.
+
+```ts
+const people = ["alice", "bob", "jan"].map((name) => ({ name } as Person));
+// 반환되는 값을 Person[]으로 단언, 그러나 좋지 않은 예제
+
+const people = ["alice", "bob", "jan"].map((name) => ({} as Person)); // 런타임시에 오류 없음
+```
+
+최종적으로 원하는 타입을 직접 명시하고, 타입스크립트가 할당문의 유효성을 검사
+
+```ts
+const people: Person[] = ["alice", "bob", "jan"].map(
+ (name): Person => ({ name })
+);
+```
+
+- 함수 호출 체이닝이 연속되는 곳에서는 체이닝 시작에서부터 명명된 타입을 가져야 정확한 곳에 오류가 표시된다.
+
+
+
+### 타입 단언이 꼭 필요한 경우
+
+- **타입 단언**은 타입 체커가 추론한 타입보다 개발자가 판단하는 타입이 더 정확할 때 의미가 있다.
+- 예를 들어, 타입스크립트는 DOM에 접근할 수 없기 때문에 DOM 엘리먼트에 대해 타입 단언을 해주는 것
+
+```ts
+document.querySeletor("#myButton").addEventListener("click", (e) => {
+ e.currentTarget; // 타입은 EventTarget
+ const button = e.currentTarget as HTMLButtonElement;
+ button; // 타입은 HTMLButtonElement
+});
+```
+
+
+
+### 자주 쓰이는 특별한 문법(!)을 사용해서 `null`이 아님을 단언
+
+```ts
+const eNull = document.getElementById("foo"); // 타입은 HTMLElement | null
+const el = document.getElementById("foo")!; // 타입은 HTMLElement
+```
+
+- 접미사로 쓰이는 `!`는 그 값이 `null`이 아니라는 단언문으로 해석
+
+---
+
+> 최근 프로덕트 코드에서 서버로부터 받아오는 값을 잘 보여주기 위해 가공해야했는데 `Array.prototype.find`를 써서 원치않는 `undefined`가 발생하는 경우가 생겨서 **타입 단언**을 사용했다. 이에 대해 얘기를 나눴는데 `undefined`가 없을 거라고 단정짓지 않고 `if`문을 써서 해당 경우는 `throw New Error()`를 하는 게 낫다는 의견을 들었다. 서버를 믿지말고, 나를 믿지 않을 것!
+
+
+
+
+## 아이템 10. 객체 래퍼 타입 피하기
+
+- 자바스크립트에는 **자동 형반환**이라는 속성이 있는데, 예를 들어 기본형 `string`과 객체 타입 `String`을 서로 자유롭게 변환한다. `string` 기본형에 `charAt` 같은 메서드를 사용할 때, 자바스크립트는 기본형을 `String` 객체로 래핑(wrap)하고 메서드를 호출하고, 마지막에 래핑한 객체를 버린다.
+
+
+
+### 객체 래퍼 타입의 자동 변환
+
+```js
+> x = "hello"
+> x.language = "English"
+'English'
+
+> x.language
+undefined
+```
+
+이 코드는 실제로 `x`가 `String` 객체로 변환된 후 `language` 속성이 추가되었고, `language` 속성이 추가된 객체는 버려진 것
+
+
+
+- 다른 기본형 `number, boolean, symbol, bigint`에도 객체 래퍼 타입이 존재 (`null`과 `undefined`에는 없음)
+- 타입스크립트는 기본형과 객체 래퍼 타입을 별도로 모델링
+
+ - `string`과 `String`
+ - `number`와 `Number`
+ - `boolean`과 `Boolean`
+ - `symbol`과 `Symbol`
+ - `biginit`과 `Biginit`
+
+
+
+### 타입스크립트 객체 래퍼 타입은 지양하고, 대신 기본형 타입을 사용
+
+대부분의 라이브러리와 마찬가지로 타입스크립트가 제공하는 타입 선언은 전부 **기본형 타입**으로 되어 있다.
+
+
+
+
+## 아이템 11. 잉여 속성 체크의 한계 인지하기
+
+_아이템 7. 타입이 값들의 집합이라고 생각하기_ 와 이어지는 내용
+
+타입이 명시된 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 속성이 있는지, 그리고 **그 외의 속성은 없는지** 확인
+
+```ts
+interface Room {
+ numDoors: number;
+ ceilingHeightFt: number;
+}
+
+const r: Room = {
+ numDoors: 1,
+ ceilingHeightFt: 10,
+ elephant: "present", // 오류, 객체 리터럴은 알려진 속성만 지정할 수 있으며 'Room'형식에 'elephant' 속성이 없습니다.
+};
+
+const obj = {
+ numDoors: 1,
+ ceilingHeightFt: 10,
+ elephant: "present",
+};
+const r: Room = obj; // 정상
+```
+
+- `obj` 타입은 `Room` 타입의 부분 집합을 포함하므로, `Room`에 할당 가능하며 타입 체커도 통과
+
+
+
+### 잉여 속성 체크 이용의 한계
+
+- 객체 리터럴이 아닌 경우에는 **잉여 속성 체크**가 되지 않는다.
+
+```ts
+interface Options {
+ title: string;
+ darkMode?: boolean;
+}
+
+const o1: Options = document; // 정상
+
+const o2: Options = {
+ darkmode: true,
+ title: "Ski Free",
+}; // 에러, 'Options' 형식에 'darkmode'가 없습니다.
+```
+
+
+
+- 잉여 속성 체크는 타입 단언문을 사용할 때 적용되지 않는다.
+
+```ts
+const o = { darkmode: true, title: "Ski Free" } as Options; // 정상
+```
+
+```ts
+interface LineChartOptions {
+ logscale?: boolean;
+ invertedYAxis?: boolean;
+ areaChart?: boolean;
+}
+
+const opts = { logScale: true };
+const o: LineChartOptions = opts;
+// 에러, '{ logScale: true }' 유형에
+// 'LineChartOptions' 유형과 공통적인 속성이 없습니다.
+```
+
+구조적인 관점에서 선택적 속성만 가지는 '약한(weak)' 타입에도 비슷하게 체크가 동작한다. 공통 속성 체크는 잉여 속성 체크와 마찬가지로 오타를 잡는데 효과적이며 구조적으로 엄격하지 않다. 하지만 잉여 속성 체크와 다르게, 약한 타입과 관련된 할당문마다 수행된다. 임시 변수를 제거하더라도 공통 속성 체크는 여전히 동작한다.
+
+---
+
+- 객체 리터럴을 변수에 할당하거나 함수에 매개변수로 전달할 때 잉여 속성 체크가 수행된다.
+- 잉여 속성 체크에는 한계가 있다는 걸 인지하며 사용해야한다.