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/seongho.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/seongho.md" index 3beced8..10d4630 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/seongho.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/seongho.md" @@ -1 +1,259 @@ - +## 타입스크립트만의 독자적 타입 시스템 +ts에서 내포하고 있는 개념은 모두 js에서 기인한 것 임
+ts의 `any`타입을 살펴보자. js에서 변수 타입을 아무리 추적해봐도, any라는 문자열을 반환하는 경우는 찾을 수 없음. `any`는 ts만의 독자적인 타입 시스템이기 때문.
+ +타입스크립트의 타입 계층구조는 아래와 같음. +typeHierarchy image of typescript + +
+ +### 1. `any`타입 +any타입은 앞서 말한대로 js에 존재하는 모든 값을 오류없이 받을 수 있음.
+따라서 any로 지정한 타입에 어떠한 값을 할당하더라도 오류가 발생하지 않음. +```ts +let a: any; + +a = 1; +a = 'Hello'; +a = () => {}; +a = {}; +``` +이러한 any는 사실 ts의 정적 타이핑의 방향과는 맞지 않기때문에 최대한 사용을 지양해야 함.
+하지만 어쩔수 없는 환경이라는 것이 있는 법. 대표적으로 3가지 경우가 있음. + +- **개발 단계에서 임시로 값을 지정해야 하는 경우**
+ 아직 API의 세부 스펙이 나오지 않았거나, 확정되지 않았을 경우 `any`타입을 임시로 할당해 준 뒤, 이후 세부 스펙이 나왔을 때 다른 타입으로 대체하는 경우가 많음. + +
+ +- **어떤 값을 받아올지 또는 넘겨줄지 정할 수 없을 경우**
+ _API 요청 및 응답 처리_, _콜백함수 전달_, _타입이 잘 정제되지 않아 파악이 힘든 외부 라이브러리_ 를 사용하는 경우 `any`타입을 사용할 수 있음. + + ```ts + type ModalParams = { + show: boolean; + content: string; + action?: any; + } + ``` + `ModalParams`를 보면 `action`타입이 `any`로 선언되어져 있는데, 모달의 특성상 모든 액션에 인자의 갯수나, `return`값을 모두 명시해줄 수 없을 때 `any`를 사용할 수 있음. + +
+ +- **값을 예측할 수 없을 경우 암묵적으로 사용**
+ fetch와 API는 요청 이후 응답을 특정 포맷으로 파싱하는데, 이때 반환 타입이 any로 매핑되어져 있음. + ```ts + async function fetchAPI() { + const res = await fetch('https://api.com'); + const data = await res.json(); // res.json()의 타입은 Priomise + + return data; + } + ``` + +
+ +> [!WARNING] +> `any`타입은 편의성과 확장성을 제공하지만 컴파일러가 에러를 잡지 못하기 때문에 실제 런타임에서 심각한 오류가 발생할 수 있으니, 최대한 사용을 지양하자 + +
+ +### 2. `unknown` 타입 +`unknown`타입은 `any`타입과 유사하게 모든 타입의 값이 할당 될 수 있음. +**_그러나 unknown타입으로 선언된 값은 any를 제외하고, 다른 타입으로 선언된 변수에 할당할 수 없음_** + +> [!NOTE] +> **`any` vs `unknown`**
+> | any | unknown | +> |--|--| +> | - 어떤 타입이든 any에 할당 가능
- `any`타입으로 선언된 변수는 어디든 할당 가능 | - 어떤 타입이든 unknown에 할당 가능
- `unknown`타입으로 선언된 변수는 any타입 외에 다른 타입으로 선언된 변수에 할당 불가능 | +> +> + +
+ +`unknown`의 특징은 함수를 unknown타입에 할당할때는 컴파일러가 경고를 주지는 않지만, 실행하려고 하면 에러가 발생함. + +-> 원시값의 사용은 에러를 뱉지 않지만 함수, 객체, 배열로 접근하려고 하면 에러를 뱉음 + +앞서, `any`를 사용하는 경우중에 어떤 값이 할당될지 파악하기 어려운 상황에서 `any`타입을 임시로 지정하여 개발하다가, 추후 any타입을 수정해야 하는 것을 **깜빡하고 누락하면** 큰일이 발생함.
+타입이 식별된 후에 사용이 가능한 unknown타입은 이런 불상사를 보완하기 위해서 등장한 타입임.
+따라서 `any`타입 대신에 `unknown`으로 대체해서 사용하는 방법이 권장 됨. + +
+ +### 3. `void` 타입 +함수가 아무것도 반환하지 않는 경우에 사용하는 타입. (함수가 아닌 곳에서도 할당이 가능하지만, 무의미함) +```ts +function runCallback(callback: CallbackType): void { + callback(); +} +``` +js에서 아무것도 리턴하지않으면 암묵적으로 `undefined`를 리턴하지만 이건 `void`와는 다름.
+명시적인 의미를 부여하는 관점에서 `undefined`와 `null`, `void`를 의미에 맞게 사용하자. + +
+ +### 4. `never` 타입 +never타입도 일반적으로 함수와 관련해서 많이 사용되는 타입으로서, **값을 반환할 수 없는 타입**을 말함.
+여기서 중요한 건 반환을 **`안`하는 거**랑 **`못`하는 거**를 명확히 구분 해야 함. +**못하는 경우**는 대표적으로 두가지 경우가 있음. +- 에러를 던지는 경우
+ ```ts + function generateError(): never { + throw new Error(); + + // ... + } + ``` +- 무한히 함수가 실행되는 경우(infinity loop)
+ ```ts + function infiniteLoop(): never { + while (true) { + // do something.. + } + } + ``` +
+ +`never`타입은 모든 타입의 하위 타입으로서 never로 선언된 변수에는 어떠한 타입도 할당될 수 없음. +ts에서는 조건부 타입을 결정할 때 엄격한 타입검사 목적으로 never타입을 명시적으로 사용하기도 함. + +
+ +### 5. `Array`타입 +js에서의 배열은 동적 언어의 특징에 따라 어떤 값이든 배열의 원소로 허용함. + +```tsx +function fn() {}; + +const arr = [1, "string", fn]; +``` + +하지만 이런 개념은 ts의 정적타이핑에 부합하지 않음. + +따라서 ts에서는 배열의 크기까지 제한하지는 않지만, 정적타입의 특성을 살려 +명시적인 타입을 선언하여 해당 타입의 원소를 관리하는 것을 강제함. + +```ts +const arr: number[] = [1, 2, 3]; +``` + +→ 숫자에 해당하는 원소만 허용함.
+Array는 `제네릭`이라는 특수한 문법으로도 선언이 가능함. + +```ts +const arr: Array = [1, 2, 3]; +``` + +두 선언방식의 차이점은 없음.
+만약, 여러 타입을 모두 관리해야 하는 배열을 선언하려면 `유니온 타입`을 사용할 수 있음 + +```ts +const arr: Array = [1, "string"]; +const arr2: (number | string)[] = [1, "string"]; +``` + +
+ +그러나 여기에 **배열의 길이**까지 제한하고 싶다면 `튜플` 이라고 하는 타입 시스템을 사용할 수 있음. +튜플은 배열의 길이까지 제한하여 **원소타입**과, **갯수**를 보장함. +```ts +let tuple: [number] = [1]; + +tuple = [1, 2]; // Error! +tuple = ['string']; // Error! + +let tuple2: [number, string] = [1, 'string']; // ✅ +``` +튜플은 컨벤션을 잘 지키고, 배열 원소의 명확한 의미와 쓰임을 보장하면 더욱 안전하게 사용할 수 있음. + +***예를 들어 리액트의 `useState` 훅을 살펴보자.***
+`useState훅`은 튜플 타입을 반환함. +`첫번째 원소`는 훅으로부터 생성 및 관리되는 상태 값을 의미하고, `두번째 원소`는 해당 상태를 조작할 수 있는 setter를 의미함. +또한 `구조 분해 할당`을 사용해서 사용자가 자유롭게 이름을 정의할 수 있음.
+`useState`는 **반환값이 명확**하고, **잘 설계된 API**이므로 `튜플` 타입을 통해서 유연성을 얻을 수 있음. + +
+ + 튜플과 배열의 성질을 혼합해서 사용할 수도 있는데 일부는 튜플로 엄격하게 제한하고, 나머지는 배열처럼 동작하게 할 수도 있음. + ```ts + // 첫번째 원소는 number타입, 나머지는 string만 올 수 있음 + type TupleAndArray = [number, string, ...string[]]; + + function some(arr: TupleAndArray) { + // do something.. + } + ``` + + +> [!TIP] +> **`옵셔널(optional)`**
+> 선택적으로 속성을 명시하고 싶다면 물음표 기호(`?`)와 함께 해당 속성을 선언할 수 있음.
+> 이는, 옵셔널하기 때문에 필수적으로 자리잡고 있지 않을 수 있음을 의미함. +> ```tsx +> const arr: [number, string, boolean?] = [1, "Hello"]; +> ``` + +
+ +### 6. `enum` 타입 +enum타입은 `열거형`이라고도 부르는데, ts에서 지원하는 특수한 타입임. +enum을 사용해서 열거형을 정의할 수 있는데 열거형은 각각의 `멤버` 라는 것을 가짐.
+약간 객체와 비슷한데, **_ts는 각 멤버의 값이 없다면 스스로 추론함._**
+기본적인 추론 방식은 숫자 0부터 1씩 늘려가면서 값을 할당함. + +```ts +enum enumValue { + ts, + js, + react, + next, +} + +console.log(enumValue.ts); // 0 +// 역방향으로도 접근이 가능함 +console.log(enumValue[0]); // 'ts' +``` +
+ +당연하게도 각 멤버에 명시적으로 값을 할당하는 것도 가능함.
+그리고 일부 멤버에 값을 할당하지 않아도, 이전 멤버 값의 숫자를 기준으로 1씩 늘리면서 자동으로 할당함.
+**_(그래서 값을 일부만 명시적으로 할당하는 경우 명시적으로 할당하는 마지막 멤버는 숫자를 할당해야 함)_** + + +근데 enum은 숫자로만 이루어져 있거나, ts가 자동으로 추론한 열거형은 안전하지 않은 결과를 낳을 수 있음. +역방향으로 접근 할 시 범위를 넘어서 접근하더라도 에러가 발생하지 않음. +```ts +enum EnumValue { + ONE, + TWO, +} + +EnumValue[100]; // ✅ undefined +``` + +그래서 이러한 동작을 막기 위해서 `const enum`으로 enum을 선언하는 방법이 있음.
+**`const enum`은 역방향 접근을 허용하지 않음.** + +```ts +const enum EnumValue { + ONE, + TWO, +} + +console.log(EnumValue[1]); // Error : A const enum member can only be accessed using a string literal. +``` + +
+ +> [!CAUTION] +> **_"const enum으로 선언하더라도, 숫자상수로 관리되는 열거형은 선언값 이외의 값을 할당하거나, 접근할때 이를 방지하지 못한다.
+반면 문자열 상수 방식으로 열거형을 사용하는 것은 접근을 방지한다."_**
+-> 이렇게 책에 적혀져 있는데, 테스트 결과 숫자 상수 열거형도 선언값 이외의 값에 접근이 불가함❗️❗️❗️❗️ + + +enum의 가장 큰 문제는 enum이 타입 공간과, 값 공간에 모두 사용되는 타입이고 컴파일을 하면 `즉시실행함수(IIFE)`로 변환이 되는 것을 보았음.
+ +이 때문에 일부 번들러에서 사용되지 않는 `enum`이라고해도 `즉시실행함수`이기 때문에 `트리 쉐이킹` 과정중 사라지지 않는 문제가 발생함. +이는 곧 **번들 사이즈의 증가**로 이어짐 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/seongho.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/seongho.md" index 3beced8..8482a71 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/seongho.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/seongho.md" @@ -1 +1,312 @@ - +## 타입 조합 +앞에서 다룬 개념을 응용하거나, 내용을 덧붙여서 좀 더 심화한 타입 검사를 수행해보자 + +
+ +### 1. 교차 타입(Intersection) +`교차 타입`을 사용하면 여러가지 타입을 결합하여 하나의 단일 타입으로 만들 수 있음.
+교차 타입은 `&`을 사용해서 표기함. +```ts +interface Person { + name: string; + age: number; +}; + +type PersonWithLocation = Person & { location: string }; +``` + +
+ +### 2. 유니온 타입(Union) +교차 타입의 A & B가 타입 A와 타입 B를 모두 만족하는 경우라면, `유니온 타입`은 타입 A 또는 타입 B중 하나가 될 수 있는 타입을 말함. +```ts +interface Person { + name: string; + age: number; +}; + +interface Duck { + name: string; + leg: boolean; +} + +type C = Person | Duck; + + +function foo(bar: C) { + bar.name; + bar.leg; // Error : Property 'leg' does not exist on type 'Person'. +} +``` +해당 예시를 보면 bar는 `Person`과 `Duck`의 유니온 타입인 `C`를 bar의 타입으로 선언해주었음.
+근데, bar는 `Person`일지, `Duck`일지 모르는 상황이기 때문에 두 타입이 공통으로 갖는 name에는 접근이 가능하지만 `Duck`만 갖고있는 `leg` 프로퍼티에는 접근할 수 없음. + +
+ +### 3. 인덱스 시그니처(Index Signatures) +`인덱스 시그니처`는 **_특정 타입의 속성 이름은 알 수 없지만, 속성과 속성값의 타입을 알고있을 때_** 사용하는 문법.
+인터페이스 내부에 `[key: T]: K` 꼴로 타입을 명시해줌.
+이는 key는 `T`타입이여야 하고, value는 `K`타입이어야 함을 의미함. +```ts +interface IndexSignature { + [key: '']: number; +} + +let obj: IndexSignature; + +obj = { name: 1 }; +obj = { name: true }; // Error : Type 'boolean' is not assignable to type 'number'. +``` +당연하게 `유니온 타입`도 가능함. +```ts +interface IndexSignature { + [key: string]: number | string; +} + +let obj: IndexSignature; + +obj = { name: 'seongho', age: 27 }; // ✅ + +interface IndexSignature2 { + [key: string | number]: number; +} + +let obj2: IndexSignature2; + +obj2 = { 1 : 1 }; // ✅ + +``` + +> [!CAUTION] +> 인덱스 시그니처의 key의 타입은 `string`, `number`, `symbol`, `템플릿 리터럴`타입만 가능함.
+> ```ts +> interface IndexSignature { +> [key: boolean]: number | string; // Error : An index signature parameter type must be 'string', 'number', 'symbol', or a template literal type. +> } +> +> let obj: IndexSignature; +> +> obj = { name: 'seongho', age: 27 }; +> ``` + +
+ +### 4. 인덱스 엑세스 타입(Index Access Types) +`인덱스 엑세스 타입`은 말 그대로 인덱스로 접근해서 타입을 가져오는 것임.
+인덱스에 사용되는 타입도 그 자체로 타입이라서 `유니온`이나 `keyof`, `타입 별칭(type키워드로 선언한 타입)`등 모두 가능함. +```ts +interface IndexAccess { + a: number; + b: string; + c: boolean; +} + +type A = IndexAccess['a']; // number; +type B = IndexAccess['a' | 'b']; // number | string; +type C = IndexAccess[keyof IndexAccess]; // number | string | boolean; + +type typeAlias = 'b' | 'c'; // 타입 별칭 + +type D = IndexAccess[typeAlias]; // string | boolean; +``` + +인덱스 엑세스 타입은 **배열의 요소 타입**을 조회하기 위해 사용되기도 함.
+```ts +const arr = [1, 'name', true]; +type StringList = string[]; + +type ItemType = typeof arr[number]; // number | string | boolean +type ItemType2 = StringList[number]; // number + +// ====================== + +const me = [ + { name: 'seongho', age: 27 }, +]; + +type InformationOf> = T[number]; + +const seongho100: InformationOf = { + name: '오성오', + age: 100, +} +``` + +
+ +### 5. 맵드 타입(Mapped Types) +js에서의 map이라고 하면, 배열 A를 기반으로 새로운 배열 B를 만들어 내는 배열 메서드임.
+이처럼 ts에서의 `맵드 타입`도 ***다른 타입을 기반으로 한 타입을 선언할 때 사용하는 문법*** 임. 이때 `인덱스 시그니처` 문법을 사용하면 더욱 효과적으로 사용할 수 있음. +```ts +type Example = { + a: string; + b: number; + c: boolean; +} + +type Subset = { + [K in keyof T]?: T[K]; +} + +const list = [ + { name: 'seongho', age: 27 }, +] + +const withLoc = { name: 'seongho', age: 27, location: 'gp' }; + +const a: Subset = { a: 'string' }; +const b: Subset = { b: 2 }; +const c: Subset = withLoc; +``` +
+ +특이한 점은 `맵드 타입`에서 타입을 매핑할때는 `readonly`나 `?`를 수식어로 적용할 수 있다는 점인데, 추가하는 것은 물론이고 빼는것도 가능함. +```ts +type Example = { + a: string; + b: number; + c: boolean; +} + +type Subset = { + [K in keyof T]?: T[K]; +} + +// Subset에서 추가한 optional을 제거 +type Require = { + [K in keyof T]-?: T[K]; +} + +const a: Subset = { a: 'string' }; +let b: Require>; + +b = { b: 2 }; // Error! +b = { a: 'a', b: 1, c: true }; // ✅ +``` + +
+ +덧붙여서 `as`키워드를 통해서 key의 이름을 재지정 할 수도 있음. +```ts +type Example = { + a: string; + b: number; + c: boolean; +} + +type Keys = keyof Example; + +type WithOptionalSeonghoInKey = { + [K in Keys as `${K}_Seongho`]?: { + name: string; + age: number; + } +} + +const obj: WithOptionalSeonghoInKey = { + a_Seongho: { + name: '에이성호', + age: 27, + }, + b_Seongho: { + name: '비성호', + age: 25, + } +} +``` + +
+ +### 6. 템플릿 리터럴 타입(Template Literal Types) +`템플릿 리터럴 타입`은 js의 템플릿 리터럴 문자열(``)을 사용해서 문자열 리터럴 타입을 선언할 수 있는 문법임.
+위에서 본 예시에 템플릿 리터럴 타입도 같이 포함되어져 있음. 조금 더 간단한 예시로 다시 봐보자 + + +이처럼 `템플릿 리터럴`을 사용해서 변수자리에 `문자열 리터럴 유니온 타입`을 넣으면, 각 유니온 타입의 멤버들이 차례대로 해당 변수로 들어가서 재가공 됨. + +
+ +### 7. 제네릭(Generic) +제네릭은 보통 C나 Java와 같은 정적 언어에서 타입간의 재사용성을 높이기 위해서 사용하는 문법임. ts도 `정적 타입`을 가지는 언어이기때문에 `제네릭` 문법을 지원하고 있음.
+ +ts의 제네릭을 조금 더 풀어서 보면 `함수`, `타입`, `클래스` 등에서 내부적으로 사용할 타입을 미리 정해두지 않고, 타입 변수를 사용해서 해당 위치를 비워둔 뒤 실제로 해당 값을 사용할 때 외부에서 `타입 변수` 자리를 사용해 타입을 지정해서 사용하는 방식임.
+`타입 변수`는 주로 ``와 같이 꺾쇠 괄호 내부에 정의하고, 매개변수를 넣는것과 유사하게 원하는 타입을 넣어주면 됨.
+ +```ts +type ArrayType = T[]; + +const stringArray: ArrayType = ['hello', 'world']; +``` + +> [!TIP] +> **제네릭의 컨벤션**
+> 보통 타입 변수명으로 `T(Type)`, `E(Element)`, `K(Key)`, `V(Value)`등 한글자로 된 이름을 많이 사용함. + +> [!CAUTION] +> **`any`와 `제네릭`은 달라요**
+> 둘의 명확한 차이점은 배열을 예로 들어보면 편한데, `any`타입의 배열에는 배열 요소들이 전부 같지 않을 수 있음
+> 하지만 제네릭은 `any`처럼 아무 타입이나 무분멸하게 받는게 아니라, 배열의 생성 시점에 원하는 타입으로 특정하는 것임. +> ```ts +> type AnyArray = any[]; +> type ArrayType = T[]; +> +> const list1: AnyArray = [1, 'hello', true, () => {}]; // 아무거나 가능 +> const list2: ArrayType = [1, 2, 3, 4]; +> const list3: ArrayType = [1, 'hello', true, () => {}]; // > Error! +> ``` + +
+ +제네릭 함수를 호출 할 때 ***반드시*** 꺽쇠괄호 안에 타입을 명시해줘야 되는 것은 아님. 타입을 명시하는 부분을 생략하면 컴파일러가 `인자`를 보고 타입을 추론 해줌. + +-> 인자에 string타입의 값이 들어와서 컴파일러가 제네릭 함수에 들어온 인자값을 보고 타입을 스스로 추론했음. + +만약 특정 요소의 타입을 알 수 없는 경우에는 `타입 기본값`도 할당해 줄 수 있음. +
+
+
+ +***제네릭을 사용할때 항상 유의헤야 하는 점은 제네릭에는 어떤 타입이든 올 수 있다는 점임.***
+이걸 왜 유의해야 하냐? 이는 곧, **특정 타입에만 존재하는 프로퍼티나 메서드를 참조하려고 하면 안된다는 뜻**임!!
+예를 들자면 +```ts +function genericFunc(params: T): number { + return params.length; // Error : Property 'length' does not exist on type 'T'. +} +``` +이런거임.
+ +`length`는 배열에만 존재하는 프로퍼티고, T에는 어떤 타입이 올지 모르기 때문. 이 문제는 기본 타입을 할당해줘도 해결이 안됨. +```ts +function genericFunc(params: T): number { + return params.length; // Error : Property 'length' does not exist on type 'T'. +} +``` +
+ +만약, 어떤 타입이 올지 모르지만 `length` 프로퍼티는 반드시 갖는 프로퍼티만 오게 하고 싶다면, 제약을 걸어서 만족시켜줄 수 있음. +```ts +interface HasLengthProperty { + length: number; +} + +function genericFunc(params: T): number { + return params.length; +} + +function foo(a: number, b: string, ...params: unknown[]) { + genericFunc(arguments); // arguments는 유사 배열이므로 length 프로퍼티를 가지기 때문에 가능. + genericFunc(params); // 배열도 가능. 배열도 js에서는 객체니까 + genericFunc({ + length: 1, + name: 'seongho' + }); // length프로퍼티를 갖고 있으니까 이것도 가능 +} +``` + +> [!CAUTION] +> **tsx파일에서 화살표 함수에 제네릭을 사용하면 에러가 발생함**
+> 제네릭의 꺾쇠 괄호와 태그의 꺾쇠괄호를 구분할 수 없기 때문임.
+> 아래 이미지를 참고하자.
+>
+> \ No newline at end of file diff --git "a/assets/CH03/any\354\231\200unknown.jpeg" "b/assets/CH03/any\354\231\200unknown.jpeg" new file mode 100644 index 0000000..63266cb Binary files /dev/null and "b/assets/CH03/any\354\231\200unknown.jpeg" differ diff --git a/assets/CH03/arrow_function_generic.png b/assets/CH03/arrow_function_generic.png new file mode 100644 index 0000000..ab4257a Binary files /dev/null and b/assets/CH03/arrow_function_generic.png differ diff --git a/assets/CH03/different_book.jpeg b/assets/CH03/different_book.jpeg new file mode 100644 index 0000000..29c35dc Binary files /dev/null and b/assets/CH03/different_book.jpeg differ diff --git a/assets/CH03/enum_a_ju_C.jpeg b/assets/CH03/enum_a_ju_C.jpeg new file mode 100644 index 0000000..33b69ca Binary files /dev/null and b/assets/CH03/enum_a_ju_C.jpeg differ diff --git a/assets/CH03/generic_default.png b/assets/CH03/generic_default.png new file mode 100644 index 0000000..87dac20 Binary files /dev/null and b/assets/CH03/generic_default.png differ diff --git a/assets/CH03/generic_type_inference.jpeg b/assets/CH03/generic_type_inference.jpeg new file mode 100644 index 0000000..ee730d9 Binary files /dev/null and b/assets/CH03/generic_type_inference.jpeg differ diff --git a/assets/CH03/template_literal.jpeg b/assets/CH03/template_literal.jpeg new file mode 100644 index 0000000..ae76c31 Binary files /dev/null and b/assets/CH03/template_literal.jpeg differ diff --git a/assets/CH03/typeHierarchy_of_typescript.jpeg b/assets/CH03/typeHierarchy_of_typescript.jpeg new file mode 100644 index 0000000..eb9f6fd Binary files /dev/null and b/assets/CH03/typeHierarchy_of_typescript.jpeg differ diff --git a/assets/CH03/typle_and_array.jpeg b/assets/CH03/typle_and_array.jpeg new file mode 100644 index 0000000..8df1532 Binary files /dev/null and b/assets/CH03/typle_and_array.jpeg differ diff --git a/assets/CH03/unknown_test.jpeg b/assets/CH03/unknown_test.jpeg new file mode 100644 index 0000000..f7af45b Binary files /dev/null and b/assets/CH03/unknown_test.jpeg differ