diff --git "a/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.1_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\353\237\260\355\203\200\354\236\204\352\263\274_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\354\273\264\355\214\214\354\235\274/seongho.md" "b/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.1_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\353\237\260\355\203\200\354\236\204\352\263\274_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\354\273\264\355\214\214\354\235\274/seongho.md" index 3beced8..00e2a53 100644 --- "a/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.1_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\353\237\260\355\203\200\354\236\204\352\263\274_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\354\273\264\355\214\214\354\235\274/seongho.md" +++ "b/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.1_\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\353\237\260\355\203\200\354\236\204\352\263\274_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270\354\235\230_\354\273\264\355\214\214\354\235\274/seongho.md" @@ -1 +1,60 @@ - +### 런타임과 컴파일타임 +--- +프로그래밍 언어는 일반적으로 `고수준`과 `저수준`으로 구분됨. +- 고수준 : 사람이 이해하기 쉬운 형식으로 작성된 언어 +- 저수준 : 컴퓨터가 이해하기 쉬운 형식으로 작성된 언어 + +js는 대표적인 고수준 언이이며, 컴파일러에 의해서 저수준 언어로 변역되어서 실행됨. + +개발자가 소스코드를 작성하고, 해당 코드는 컴파일러에 의해서 기계어 코드로 변환되어 실행이 가능한 프로그램이 되는데, 이를 `컴파일타임`이라고 함.
+> [!NOTE] +> **컴파일타임**
+> 소스코드가 컴파일 과정을 거쳐서 컴퓨터가 이해할 수 있는 기계어로 바뀌어 실행될 수 있는 프로그램이 되는 괴정. + +소스코드가 컴파일이 되어 기계어 코드가 되면 프로그램이 메모리에 적재되어서 실행되는데, 이 시간을 `런타임`이라고 함. +> [!NOTE] +> **런타임**
+> 컴파일 과정을 마친 응용 프로그램이 사용자에 의해 실행되는 과정. + +
+ +### js런타임 +--- +js 런타임은 js가 실행되는 환경을 말함.(대표적으로 `브라우저`, `nodeJS`가 있음)
+런타임은 다양한 구성요소로 이루어져 있음(js엔진, webAPI, 이벤트루프, 콜백큐 등등..) + +-> js런타임 구성요소 + +
+ +### 타입스크립트의 컴파일 +--- +일반적으로 **"컴파일"** 은 고수준 언어에서 저수준 언어로 변환되는 과정을 가리킴.
+ +타입스크립트는 tsc라는 컴파일러를 통해서 js코드로 변환됨. 하지만 ts는 고수준 언어에서 고수준 언어로(ts to js) 변환되는 것 이기 떄문에 컴파일이 아닌, `트랜스파일` 또는 `source-to-source compiler`라고도 함. + +> [!NOTE] +> 트랜스파일의 다른 예시로 C/C++ 코드를 js로 변환하는 `Emscripten`과, `Babel`을 들수있음. + +타입스크립트는 `.ts` 파일을 찾아내서 컴파일한 뒤 `.js`파일로 만들어냄. +이때 tsc는 소스코드를 해석해서 `AST(추상 구문 트리)`를 만들고 이후 타입 확인을 거친 뒤에 js코드인 `결과 코드`를 생성함.
+tsc가 ts코드를 컴파일해서 프로그램이 실행되기 까지의 과정은 아래와 같음. + +
    +
  1. 타입스크립트 소스코드를 AST(추상 구문 트리)로 만듬 (tsc)
  2. +
  3. 타입 검사기가 AST를 확인해서 타입을 확인 함 (tsc)
  4. +
  5. 타입스크립트 AST를 JS소스코드로 변환함(tsc)
  6. +
  7. js소스코드를 AST로 만듦 (런타임)
  8. +
  9. AST가 바이트 코드로 변환 됨 (런타임)
  10. +
  11. 런타임에서 바이트 코드가 실행됨 (런타임)
  12. +
+ +> [!NOTE] +> **AST(추상 구문 트리)**
+> 컴파일러가 소스코드를 해석하는 과정에서 생성되는 데이터 구조.
+> 컴파일러는 `어휘적 분석`과, `구문 분석`을 통해 소스코드를 노드 단위의 트리 구조로 형성함. 이를 AST라고 함. + +
+ +타입스크립트의 타입은 최종적으로 만들어지는 프로그램에는 아무런 영향을 주지 않음. 또한 ts는 컴파일 타임에 타입을 검사하기 때문에 에러가 발생하면 프로그램이 실행되지 않음.
+이러한 특징 떄문에 ts를 `정적 타입 검사기`라고 부름. \ No newline at end of file diff --git "a/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\353\217\231\354\236\221/seongho.md" "b/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\353\217\231\354\236\221/seongho.md" index 3beced8..4177ae1 100644 --- "a/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\353\217\231\354\236\221/seongho.md" +++ "b/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.2_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\353\217\231\354\236\221/seongho.md" @@ -1 +1,85 @@ - +앞서 우리는 타입스크립트 컴파일 과정의 전반적인 흐름에 대해 살펴보았음.
+이번 절에서는 tsc의 주요 역할에 대해서 살펴보자 + +
+ +### 코드 검사기로서의 tsc +--- +tsc는 코드 타입에 오류가 없는지를 확인함.
+ts는 컴파일타임에 코드 타입을 확인하기 때문에 코드를 실행하지 않고도, 에러가 있다는 것을 바로알 수 있음. 따라서 ts는 정적으로 코드를 분석하여 에러를 검출하며, 코드를 실행하기 전에 에러를 사전에 알려줌.
+ +아래 예시를 살펴보자 + +```js +// js +const dev = { + work() { + console.log('work'); + } +} + +dev.sleep(); // ✅ +``` +해당 코드는 js였다면 코드를 작성하는 시점에서는 에러가 발생하지 않음. 그러나, 실제 실행을 하면 에러가 발생함.
+같은 코드를 ts로 작성하게 되면 코드를 실행하기 전에 에러를 발견해서 알려줌 + +```ts +// ts +const dev = { + work() { + console.log('work'); + } +} + +dev.sleep(); // Error! Property 'sleep' does not exist on type '{ work(): void; }' +``` +이처럼 ts는 js였다면 런타임에서 발견할 수 있는 에러를 컴파일 타임에 발견해서 실행과정에서 발생할 수 있는 문제를 방지함. + +tsc는 tsc binder를 사용해서 타입 검사를 하며, 컴파일 타임에 오류를 발견함.
+이후 타입 검사를 거쳐서 AST를 js코드로 변환함. (tsc binder는 ts깃헙에 정의되어져 있음) + +
+ +### 코드 변환기로서의 타입스크립트 컴파일러 +--- +tsc는 타입검사를 한 뒤에, 구버전의 js로 트랜스파일을 함. 이것이 tsc의 두번째 역할임.
+tsc의 `target`옵션을 사용해서 특정 버전의 js소스코드로 변환할 수 있음. + + +tsc는 타입 검사를 수행한 후 코드 변환을 시작하는데, 이때 타입 오류가 있더라도 일단 컴파일을 진행함.
+ts코드가 js코드로 변환되는 과정은 타입 검사와 독립적으로 이루어지기 때문임. +따라서 ts코드의 타이핑이 잘못되어서 발생하는 에러는 js를 실행하는 과정에서 런타임 에러로 처리 됨. +```ts +const naming: string = 'zig'; +const age: number = 'zig'; +``` +-> 해당 코드는 타입 에러가 있지만 트랜스파일은 진행 됨. + +```ts +// 컴파일 이후 js소스코드 +"use strict"; + +const naming = 'zig'; +const age = 'zig'; +``` + +ts를 컴파일하게 되면 순수js만 남고, 런타임에서는 타입 검사를 할수없기 때문에 주의해야 하는 경우도 있음. +```ts +interface Name { + name: string; +} + +function getName(name: Name) { + if (name instanceof Name) { // Error! 'Name' only refers to a type, but is being used as a value here + // ... + } +} +``` +위 코드는 `instanceof`는 런타임에 실행되지만, `Name`은 타입이기 때문에 런타임은 해당 코드를 이해하지 못함. +정리하자면 tsc의 역할은 크게 2가지로 볼수 있음. +- **코드의 타입 오류검사** +- **최신버전의 ts나 js를 구버전의 js로 트랜스파일** + +> [!TIP] +> ***그러면 바벨과는 뭐가 다른거죠?***
+> 바벨은 타입 검사를 하지 않고, 최신버전의 js코드를 구버전의 js로 컴파일 하는것이 주된 역할임. diff --git "a/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.3_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\352\265\254\354\241\260/seongho.md" "b/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.3_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\352\265\254\354\241\260/seongho.md" index 3beced8..62e53bb 100644 --- "a/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.3_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\352\265\254\354\241\260/seongho.md" +++ "b/CH06_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274/6.3_\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270_\354\273\264\355\214\214\354\235\274\353\237\254\354\235\230_\352\265\254\354\241\260/seongho.md" @@ -1 +1,112 @@ - +여기서는 실제 tsc의 구성 요소를 훑어보며 tsc의 동작 방식을 톮아보자
+ +컴파일러는 하나의 프로그램으로, 이를 구현한 소스파일이 존재함. +타입스크립트의 공식문서에서도 찾아볼 수 있음.
+-> 링크 + +tsc는 아래와 같은 5가지 단계를 거쳐서 소스 변환을 진행함. + + +
+ +### 0. 프로그램 +--- +컴파일러는 tsconfig에 명시된 컴파일 옵션을 기반으로 `'tsc'`라는 명령어로 실행됨.
+우선적으로 컴파일 과정을 관리하는 컴파일 객체가 생성되고, 해당 객체는 컴파일을 할 `ts소스파일`과, 해당 파일에서 `import`하는 파일들을 불러오는데 이때 가장 첫번재로 불러온 파일을 기준으로 컴파일을 시작함. + +
+ +### 1. 스캐너 +--- +ts코드를 js로 변환하기 위한 첫번째 단계는 `스캐너`임.
+스캐너는 ts소스 파일을 어휘적으로 분석해서 `토큰`을 생성함. 즉, 소스코드를 작은 단위로 나누어서 의미있는 토큰으로 변환하는 작업을 수행함.
+```ts +const name = 'seongho'; +``` +예를 들어서 위와 같은 코드는 아래처럼 `토큰화` 됨. + + +
+ +### 2. 파서 +--- +스캐너가 소스파일을 토큰으로 나눠주면 파서는 해당 토큰을 이용해서 `AST`를 생성함.
+`AST`는 컴파일러가 동작하는게 가장 핵심 기반이 되는 자료구조로써, 소스코드를 트리형태의 구조로 표현함. AST의 최상위 노드는 타입스크립트 소스파일이며, 마지막 리프노드는 `EOF 토큰`으로 구성됨.
+파서는 토큰을 이용해서 `구분적 분석(Syntax analysis)`을 수행함.
+AST의 각각의 노드는 `코드상의 위치`, `구문 종류`, `코드 내용`과 같은 정보를 담고있음.
+예를 들어서 토큰에 `()`에 해당하는 토큰이 있을 경우, AST를 생성하는 과정에서 해당 토큰이 **함수의 호출**인지, **함수의 인자**인지 또는 **그룹 연산자**인지가 결정 됨. + +예시를 봐보자 + + + +-> 해당 이미지는 `AST`와 함수의 이름인 `getName`에 해당하는 노드에 대한 정보를 보여주고 있음. + +
+ +### 3. 바인더 +--- +바인더의 주요 역할은 ***체커 단계(4단계)에서 타입 검사를 할 수 있도록 기반을 마련하는 것*** 임. 바인더는 타입 검사를 위해서 `심볼`이라는 데이터 구조를 생성함.
+심볼은 이전 단계의 AST에서 선언된 타입의 노드 정보를 저장함. 심볼의 구성은 아래와 같음. +```ts +export interface Symbol { + flags: SymbolFlags; + escapeName: string; + declarations?: Declaration[]; + // ... +} +``` + +
+ +여기서 `flags`는 AST에서 선언된 타입의 노드 정보를 저장하는 식별자임. +```ts +// flag에 해당하는 SymbolFlags타입\ +export const enum SymbolFlags { + None = 0, + FunctionScopedVariable = 1 << 0, // Variable(var) or parameter + BlockScopedVariable = 1 << 1, // a block-scoped variable (let, const) + Property = 1 << 2, // Property or enum member + EnumMember = 1 << 3, // Enum member + Function = 1 << 4, // Function + Class = 1 << 5, // Class + Interface = 1 << 6, // Interface + // ... +} +``` + +
+ +`declaration`필드는 AST노드의 배열 형태를 보임.
+ + + +즉, 바인더는 `심볼`을 생성하고, 해당 심볼과 그에 대응하는 AST노드를 연결하는 역할을 수행함. + +
+ +### 4. 체커와 이미터 +--- +- `check`: 확인하다 +- `emit`: 내보내다 또는 방출하다 + +`체커`는 파서가 생성한 `AST`와 `바인더`가 생성한 `심볼`을 활용해서 타입 검사를 수행함. + +체커의 주요 역할은 AST를 탐색하면서 심볼 정보를 불러와 주어진 소스 파일에 대해서 타입 검사를 진행하는 것임. 체커의 타입 검사는 다음 단계인 이미터 단계에서 실행 됨.
+checker.ts의 getDiagnostics 함수를 사용해서 타입을 검증하고, 에러가 있다면 어떤 에러를 띄울지를 저장함. + +이미터는 `타입스크립트 소스파일`을 `js소스파일`과, `타입 선언 파일d(d.ts)`로 나눠서 생성함. 이미터는 ts파일을 변환하는 과정에서 tsconfig파일을 불러오고, 체커를 통해서 코드에 대한 타입 검증 정보를 가져옴.
+ +이후 emit이라는 의미에 맞게 `emitter.ts` 내부의 `emitFiles()` 함수를 사용해서 코드 변환을 진행함. + +tsc의 컴파일 과정을 정리하자면 아래와 같음. +
    +
  1. 'tsc'라는 명령어로 프로그램 객체를 생성해서 컴파일을 시작함
  2. +
  3. 스캐너가 소스코드를 토큰으로 분해함
  4. +
  5. 파서는 해당 토큰을 기반으로 AST를 만듦
  6. +
  7. 바인더는 해당 AST를 기반으로 각각의 노드에 대한 심볼을 생성함
  8. +
  9. 체커는 AST를 순회하며 각 노드에 상응하는 심볼 정보를 가지고 타입 검사를 진행함
  10. +
  11. 이미터를 사용해서 js파일로 변환함
  12. +
diff --git "a/CH07_\353\271\204\353\217\231\352\270\260_\355\230\270\354\266\234/7.1_API_\354\232\224\354\262\255/seongho.md" "b/CH07_\353\271\204\353\217\231\352\270\260_\355\230\270\354\266\234/7.1_API_\354\232\224\354\262\255/seongho.md" index 3beced8..aa1a0e4 100644 --- "a/CH07_\353\271\204\353\217\231\352\270\260_\355\230\270\354\266\234/7.1_API_\354\232\224\354\262\255/seongho.md" +++ "b/CH07_\353\271\204\353\217\231\352\270\260_\355\230\270\354\266\234/7.1_API_\354\232\224\354\262\255/seongho.md" @@ -1 +1,219 @@ - +### fetch로 API요청하기 +--- +아래와 같은 장바구니를 조회해서 볼수 있는 코드가 있다 +```ts +const CartBadge = () => { + const [cartCount, setCartCount] = useState(0); + + useEffect(() => { + fetch('https://api.baemin.com/cart') + .then((response) => response.json()) + .then(({ cartItem }) => setCartCount(cartItem.length)); + }); + + return ( + // ... + ); +}; +``` +이렇게 코드를 작성했는데, 백엔드에서 API주소를 수정해야 한다고 한다..
+이렇게 이미 컴포넌트 내부에 깊숙이 자리잡은 비동기 호출 코드는 변경에 취약함. 또한 API를 요청할 경우 타임아웃 설정이 필요하거나, 커스텀 헤더가 필요한 경우가 있음. + +이처럼 API요청 정책이 계속 추가될때마다 계속해서 비동기 호출 코드를 수정해야 하는 번거로움이 생김. + +이러한 점을 감안한다면, 비동기 호출 코드는 따로 모듈로 분리해서(서비스 레이어로 분리해서) 작성되어야 함.
+그러나 레이어를 나누는 것만으로 위와같이 수많은 변화에 대응하기는 충분치 않음. + +
+ +### Axios 활용하기 +--- +fetch는 네이티브 라이브러리이기때문에 별도의 설치없이 사용할 수 있다는 장점이 있지만, 그만큼 모든것을 직접 구현해서 사용해야 한다는 단점이 존재함.
+따라서 `axios`라이브러리를 많이 사용함. + +***만약 `axios`를 사용한다면*** +- **여러개의 API Entry(base URL)을 사용해야 하는 경우**
+ ```ts + const defaultRequester: AxiosInstance = axios.create(defaultConfig); + const orderRequester: AxiosInstance = axios.create({ + baseUrl: ORDER_API_BASE_URL, + ...defaultConfig + }); + const caerRequester: AxiosInstance = axios.create({ + baseUrl: CART_API_BASE_URL, + ...defaultConfig + }); + ``` + 요런식으로 각각의 서로 다른 baseURL을 가진 axios인스턴스를 활용할 수 있음. + +- ***커스텀 헤더를 일괄적으로 추가하거나, 에러 핸들링을 한군데서 처리하고 싶을 경우***
+이러한 경우에는 axios의 `interceptor`를 활용할 수 있음. + ```ts + const setCustomHeader = (request: AxiosRequest) => { + // 커스텀 헤더 셋팅... + } + + const handleErrorResponse = (response: AxiosResponse) => { + // 응답 에러 핸들링.. + } + + const defaultRequester: AxiosInstance = axios.create(defaultConfig); + + // request interceptor + defaultRequester.interceptors.request.use(setCustomHeader); + + // response interceptor + defaultRequester.interceptors.response.use(handleErrorResponse); + ``` + - `request interceptor`를 설정해주면 해당 인스턴스로 요청하는 모든 비동기 호출이 해당 setCustomHeader를 거친 뒤 호출을 하게 됨.
+ - `response interceptor`를 설정해주면 해당 인스턴스의 요청에 대한 모든 응답이 콜백함수를 거치게 됨(위 예시에서는 `handleErrorResponse`) + +
+ +### 요청에 따라 다른 인터셉터 만들기 +--- +위에서 본것처럼 각각의 axios 인스턴스를 만들어서 활용할수도 있지만, 요청 옵션에 따라서 다른 인터셉터를 만들기 위해서 `빌더 패턴`을 활용한 `API builder`같은 클래스 형태로 구성하기도 함. +> [!NOTE] +> **빌더 패턴**
+> 객체 생성을 더 편리하고, 가독성있게 만들기 위한 디자인 패턴으로,
+> 주로 복잡한 객체의 생성을 단순화하고, **객체 생성 과정을 분리하여 객체를 조립하는 방법**을 제공함. + +예시를 간단하게 살펴보자면 +```ts +class API { + readonly method: HTTPMethod; + readonly url: string; + headers?: HTTPHeaders; + withCredential?: boolean; + // ... + + constructor(method: HTTPMethod, url: string) { + this.method = method; + this.url = url; + } + + call() { + const requester = axios.create(); + + if (this.withCredential) { + requester.interceptors.request.use(setToken); + // do something... + } + + // ... + + return requester.request({ ...this }); + } +} +``` +이런식으로 기본 API클래스의 호출부를 구성하고, API를 호출하기 위한 래퍼를 `빌더 패턴`으로 만드는 것. +```ts +class APIBuiler { + private _instance: API; + + constructor(method: HTTPMethod, url: string, data?: unknown) { + this._instance = new API(method, url); + + this._instance.baseUrl = DEFAULT_BASE_URL; + this._instance.headers = { + 'Content-Type': 'application/json; charset: utf-8', + } + // ... + } + + static get = (url: string) => new APIBuiler('GET', url); + static post = (url: string, data: unknown) => new APIBuiler('POST', url, data); + static put = (url: string, data: unknown) => new APIBuiler('PUT', url, data); + static delete = (url: string) => new APIBuiler('DELETE', url); + + baseURL(value: string): APIBuiler { + this._instance.baseUrl = value; + + return this; + } + + withCredentials(value: boolean) { + this._instance.withCredential = true; + + return this; + } + + // ... + + build() { + return this._instance; + } +} +``` + +위와 같은 패턴으로 제공한 `APIBuilder`는 어떻게 사용할까? +```ts +const getSomething = (name: string, size: number) => { + const api = APIBuilder.get(API_URL) + .withCredentails(true) + .params({ name, size }) + .build; + + const response = api.call(); + + return response; +}; +``` + +`빌더 패턴`의 단점으로는 `보일러 플레이트`가 굉장히 많다는 점이다.. + +
+ +### API 응답 타입 지정하기 +--- +같은 서버에서 오는 응답은 대부분 하나로 통일되있어서 하나의 Response타입으로 묶어서 사용할 수 있음.
+그러나 몇몇 예외 케이스로 응답이 없는 경우가 있을 수도 있고, 다른 응답의 형태로 올 수도 있음. 이러한 점으로 보았을 때 **응답의 타입은 요청(`APIRequester`)과는 독립적으로 관리되어야 함** + +또한 API응답이 자주 바뀌는 경우에는 `뷰 모델(View Model)`을 활용할 수 있음.
+예를 들어서 아래와 같은 코드가 있다 +```ts +const CartBadge = () => { + const [cartCount, setCartCount] = useState(0); + + useEffect(() => { + fetch('https://api.baemin.com/cart') + .then((response) => response.json()) + .then(({ item }) => setCartCount(item.length)); + }); + + return ( + // ... + ); +}; +``` +근데 여기서 만약에 **API의 응답이 `item`에서 `cartItem`으로 바뀐다고 하면** UI가 깨져버리고 말것임.. + +이러한 문제를 해결하기 위해서 `뷰 모델`을 도입할 수 있음 +```ts +interface CartListItemResponse { + name: string; +} + +interface CartListResponse { + cartItem: CartListItemResponse[]; +} + +class cartList { + readonly items: CartListResponse[]; + + constructor({ cartItem }: CartListResponse) { + this.items = cartItem; + } +} +``` +`뷰 모델`을 사용하면 API의 응답이 바뀌어도 UI가 꺠지지 않게 유지할 수 있는 대신에, ***추상화가 깊어지면서 코드가 복잡해지고 레이어를 관리하고 개발하는데 비용이 많이 든다는 단점이 존재*** 함. + +따라서 결국 API 응답이 바뀌었을 때는 클라이언트 코드를 수정하는데 들어가는 비용을 줄이면서도, 도메인의 일관성을 지킬 수 있는 절충안을 찾아야 함. + +
+ +### 런타임에서 발생하는 오류 찾아내기 +--- +ts는 `정적 검사 도구` 이므로 런타임에서 API의 응답이 ts에서 정의해둔 타입과 정말로 동일하게 오는지는 확인할 수 없음.
+ +따라서 런타임에 API 응답의 타입 오류를 방지하려면 `zod`나 `Superstruct`와 같은 라이브러리를 통해서 검증할 수 있음. diff --git a/README.md b/README.md index c452a70..4602e8d 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ | 3주차 | 3.3 제네릭 사용법 ~ 4.1 타입 확장하기 | 2025.03.25 | ✅ | | 4주차 | 4.2 타입 좁히기 - 타입 가드 ~ 4.4 Exhaustiveness Checking으로 정확한 타입 분기 유지하기 | 2025.04.01 | ✅ | | 5주차 | 5장 타입 활용하기 | 2025.04.15 | ✅ | -| 6주차 | 6.1 자바스크립트의 런타임과 타입스크립트의 컴파일 ~ 7.1 API 요청 | YYYY.MM.DD | | +| 6주차 | 6.1 자바스크립트의 런타임과 타입스크립트의 컴파일 ~ 7.1 API 요청 | 2025.04.22 | ✅ | | 7주차 | 7.2 API 상태 관리하기 ~ 7.4 API 모킹 | YYYY.MM.DD | | | 8주차 | 8장 JSX에서 TSX로 | YYYY.MM.DD | | | 9주차 | 9장 훅 ~ 10장 상태관리 | YYYY.MM.DD | | diff --git a/assets/CH06/js_runtime.png b/assets/CH06/js_runtime.png new file mode 100644 index 0000000..6c70cdb Binary files /dev/null and b/assets/CH06/js_runtime.png differ diff --git a/assets/CH06/symbol.png b/assets/CH06/symbol.png new file mode 100644 index 0000000..9185ae4 Binary files /dev/null and b/assets/CH06/symbol.png differ diff --git a/assets/CH06/tokenizing.png b/assets/CH06/tokenizing.png new file mode 100644 index 0000000..69ae820 Binary files /dev/null and b/assets/CH06/tokenizing.png differ diff --git a/assets/CH06/transfile_target.png b/assets/CH06/transfile_target.png new file mode 100644 index 0000000..fd22f07 Binary files /dev/null and b/assets/CH06/transfile_target.png differ diff --git a/assets/CH06/tsc_complie_process.png b/assets/CH06/tsc_complie_process.png new file mode 100644 index 0000000..9c710de Binary files /dev/null and b/assets/CH06/tsc_complie_process.png differ diff --git a/assets/CH06/typescript_ast.png b/assets/CH06/typescript_ast.png new file mode 100644 index 0000000..ee35164 Binary files /dev/null and b/assets/CH06/typescript_ast.png differ