woowacourse-study / 2022-thanks-giving-effective-typescript

🍂추석 연휴 집중🍂 이펙티브 타입스크립트를 읽는 모임 (✌️완주완료✌️)
6 stars 0 forks source link

2022.09.08 #5

Closed moonheekim0118 closed 2 years ago

moonheekim0118 commented 2 years ago

타스로 2행시를 해보겠읍니다.

타 타인을 위해 스 스스로를 희생하자

soyi47 commented 2 years ago

안 돼 희생하지마 😭 나 자신 먼저 지켜!

아이템 16. number 인덱스 시그니처보다는 Array, 튜플, ArrayLike를 사용하기

아이템 17. 변경 관련된 오류 방지를 위해 readonly 사용하기

아이템 18. 매핑된 타입을 사용하여 값을 동기화하기

moonheekim0118 commented 2 years ago

다른 타입에는 다른 변수를 사용하기

why?

  1. 서로 관련이 없는 두 개의 값을 분리한다.
  2. 변수명을 더 구체적으로 지을 수 있다.
  3. 타입 추론을 향상시키며, 타입 구문이 불필요해진다.
  4. 타입이 좀 더 간결해진다.
  5. let 대신 const 로 변수를 선언할 수 있다.

타입 넓히기


interface Vector3 { x: number; y: number; z: number; };
function getComponent(vector: Vector3, axis: 'x' | 'y' | 'z') {
    return vector[axis];
}

let x = 'x';
let vec = { x: 10, y: 20, z: 30 };
getComponent(vec, x) ;
// 런타임시 동작은 잘 되는데 편집기에서 아래와 같은 오류 나옴
// ~ 'string' 형식의 인수는 "x" | "y" | "z" 형식의 매개변수에 할당될 수 없습니다.

넓히기의 과정 제어하기

타입스크립트의 기본 동작(추론)을 재정의 하기

  1. 명시적 타입 구문 제공하기
  2. 타입 체커에 추가적인 문맥을 제공하는 것. (함수의 매개변수로 값을 전달하기.)
  3. const 단언문 사용하기.
const v2 = {
   x: 1 as const,
   y: 2
}
// 타입은 { x: 1 ; y: number; }

const v3 = {
   x: 1,
   y: 2
} as const

// 타입은 { readonly x:1, readonly y:2 };

타입 좁히기

const el = document.getElementById('foo');
if(el){
    el
    el.innerHTML = ' wow '.blikc();
} else {
   el
   alert('No Element');
}

타입 좁히는 방법

  1. 분기문에서 예외를 던지거나 함수를 반환하여 블록의 나머지 부분에서 변수의 타입을 좁힐 수도 있다.
  2. instanceof 를 통해서 타입을 좁힌다. (분기문)
  3. 속성 체크로 타입 체크한다. a in ab
  4. Array.isArray 같은 내장함수로 타입 좁힌다.
  5. 태그 붙여서 '태그된 유니온 or 구별된 유니온 or 서로소 유니온' 만들기
    • 서로소 유니온 타입을 사용하면, 서로 겹치지 않는 여러 경우 중 하나인 타입을 표현할 수 있다.
    • 언제 유용할까..??
      네트워크 요청: 요청은 성공하거나 실패하겠지만, 성공한 동시에 실패할 수는 없다.
      데이터베이스에서 특정 아이디를 갖는 컬럼을 쿼리: 해당 컬럼이 있거나 없지만, 있으면서 없을 수는 없다.
      어떤 파일명을 갖는 파일 내용을 읽어오는 경우: 해당 파일이 있거나 없지만, 있으면서 없을 수는 없다.
    • 서로소 유니온 타입에서는 서로 겹치는게 없다. 따라서 switch 문을 사용해서 특정 타입이면 ~ 어떤 동작을 하도록 유도할 수 있다. https://ahnheejong.gitbook.io/ts-for-jsdev/06-type-system-deepdive/disjoint-union-type
// 사용자 정의 타입가드!

function isInputElement (el: HTMLElement): el is HTMLInputElement {
    return 'value' in el;
} 

function getElementContent(el: HTMLElement){
     if(isInputElement(el){
          return el.value;
     }
}
function isDefined<T>(x: T | undefined) : x is T {
     return x !== undefined;
}
prefer2 commented 2 years ago

타: 타입스크립트를 위해 스: 스스로를 희생하자

추론 가능한 타입을 사용해 장황한 코드 방지하기

타입스크립트의 맣은 타입 구문은 사실 불필요하다.

비구조화 할당문은 모든 지역 변수의 타입이 추론되도록 한다.

타입스크립트의 변수의 타입은 일반적으로 처음 등장할 때 결정된다.

객체 리터럴을 정의할 때

const elmo: Product = {
  name: 'Elmo',
  id: '123abc',
  price: 28.99
}

함수의 반환에 타입을 명시하여 오류 방지하기

interface Vector2D { x: number, y: number }
function add(a: Vector2D, b: Vector2D){
  return {x: a.x + b.x, y: a.y+ b.y}
}

// { x:number, y: number}로 추론되어 Vector2D와 호환된다
// 입력 타입은 Vector2D인데 반환 타입은 number라 당황스러울 수 있다

다른 타입에는 다른 변수 사용하기

변수의 값은 바뀔 수 있지만 그 타입은 보통 바뀌지 않는다.

유니온 타입으로 범위를 좁힐 수는 있지만 값을 사용할 때마다 타입을 확인하는 것보다는 별도의 변수를 도입하는 것이 좋다.

타입 넓히기

상수를 사용해서 변수를 초기화할 때 타입을 명시하지 않으면 타입 체커가 타입을 결정해야 한다. 즉, 정해진 값을 가지고 할당 가능한 값들의 집합을 유추해야 한다는 뜻이다. 이러한 과정을 넓히기(winding)이라고 부른다.

interface Vector2D { x: number, y: number }

function getComponent(vector: Vector2D, axis: 'x' | 'y'){
  return vector[axis]
}

let x = 'x'; 
let vec = { x: 10, y: 20 };
getComponent(vec, x); 
// string 형식의 인수는 'x' | 'y' 형식의 매개변수에 할당될 수 없습니다.

x의 타입은 할당 시점에 넓히기가 동작하여 string으로 추론되었다.

넓히기 과정 제어하기

const x = 'x' // 타입이 'x'

타입 추론의 강도를 제어

const v: { x: 1|3|5 } = { x:1 }
const v = { x: 1, y: 2 } as const
// 타입 { readonly x: 1, readonly y: 2 }

타입 좁히기

const el = document.getElementById('foo');

if(el) { console.log('not null') }
else { console.log('null') }
function isInputElement(el: HTMLElement): el is HTMLInputElement {
  return 'value' in el;
}

실수 할 수 있는 것들

liswktjs commented 2 years ago
- Pick
    - 제너릭 타입
    - 중복된 코드를 없앤다는 관점으로, Pick을 사용하는 것은 함수를 호출하는 것에 비유할 수 있다
    - T, K 두 가지 타입을 받아서 타입을 반환한다

        ```jsx
        type Pick<T,K> = { [k in k]: T[k]};

        K는 인덱스로 사용될 수 있는 값 , 실제 T의 키의 부분집합 
        ```

    - 중복되는 것을 피하는 방법

        ```jsx
        interface SaveAction {
            type: 'save';
        }
        interface LoadAction {
            type: 'load';
        }

        type Action = SaveAction | LoadiAction;
        type ActionType = 'save' | 'load';

        -> 인덱싱을 통해서 중복 피하기 
        type ActionType = Action['type'];

        -> Pick 활용하기 
        type ActionRec = Pick<Action, 'type'>; // {type: 'save' |'load'}
        ```

- 제너릭 타입은 타입을 위한 함수와 같다
- 제너릭 타입에서 매개변수를 제한할 수 있는 방법
    - extends 이용 하면, 제너릭 매개변수가 특정 타입을 확장한다고 선언할 수 있다

    ```jsx
    interface Name {
        first: string;
        last :string;
    }

    type DancingDuo<T extends Name> = [T,T];

    const couple : DancingDuo<Name> = [
        {first 'Fred', last: 'Astaire'}
    ]
    ```

동적 데이터에 인덱스 시그니처 사용하기

number 인덱스 시그니처 보다는 Array, 튜플, ArrayLike 사용하기

변경 관련된 오류 방지를 위해 readonly 사용하기