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

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

2022.09.06 #3

Closed moonheekim0118 closed 2 years ago

moonheekim0118 commented 2 years ago

추석특집 이펙티브 타입스크립트 순항중~ 포항항ꉂꉂ(ᵔᗜᵔ*) 🛳🌊

liswktjs commented 2 years ago

타입 공간과 값 공간의 심벌 구분하기

타입스크립트의 심벌은 타입 공간이나 값 공간 중의 한 곳에 존재한다

타입 심벌과 변수 선언을 같은 단어로 하여도 관련은 없지만, 코드 상 오류가 발생할 수 있다.

타입 단언 보다는 타입 선언을 사용하기

객체 래퍼 타입 피하기

잉여 속성 체크의 한계 인지하기

interface Options {
    title: string;
    darkMode?: boolean;
} 

const o1 : Options = document;
const o2 : Options = new HTMLAnchorElement; 

함수 표현식에 타입 적용하기

moonheekim0118 commented 2 years ago

타입 연산과 제너릭 사용으로 반복 줄이기

매핑된 타입 사용하기

interface State {
  userId:string;
  pageTitle:string;
  recentFiles: string[];
  pageContents:string;
}

interface  TopNavState{
   userId:string;
  pageTitle:string;
  recentFiles: string[];
}
interface  TopNavState{
   userId: State[userId];
  pageTitle: State[pageTitle];
  recentFiles: State[RecentFiles];
}

제네릭 타입


type Pick<T, K> = {
    [k in K]: T[k]
}
// K 타입은 'string | number | symbol ' 타입에 할당 할 수 없습니다.

type Pick<T, K extends keyof T> = {
    [k in K]: T[k]
}

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

인덱스 시그니쳐의 문제점

  1. 잘못된 키를 포함해 모든 키를 허용한다.
  2. 특정 키가 필요하지 않다.
  3. 키마다 다른 타입을 가질 수 없다.
  4. 타입스크립트 자동완성 기능이 지원되지 않는다.

인덱스 시그니쳐를 사용 해야 하는경우

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

interface Array<T>{
    // ...
    [ n:number] : T
}

이렇게 말이다.

ArrayLike

interface ArrayLike<T> {
  readonly length: number
  readonly [n: number]: T
}
prefer2 commented 2 years ago

잉여 속성 체크의 한계 인지하기

타입이 명시된 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 속성이 있는지 그리고 그 외의 속성은 없는지 확인한다.

interface Room {
    numDoors: number;
    ceilingHeightFt: number;
}

const obj = {
  numDoors: 1,
  ceilingHeightFt: 10,
  elephant: 'wow'
};

const r: Room = obj; // 정상

const room: Room = {
   numDoors: 1,
  ceilingHeightFt: 10,
  elephant: 'wow'
} 
// Type '{ numDoors: number; ceilingHeightFt: number; elephant: string; }' 
// is not assignable to type 'Room'.

두번째 예시에서는 잉여 속성 체크 과정이 수행되었다. 하지만 첫번째 예시에서는 아니다. 이는 잉여 속성 체크가 할당 가능 검사와는 별도의 과정이기 때문이다.

const o = { darkmode: true, title: 'Sky' } as Options; // 정상

잉여 속성 체크는 타입 단언문을 사용할 때도 적용되지 않는다. 이는 단언문보다 선언문을 써야하는 또 다른 이유이다.

잉여 속성 체크가 일어나는 경우

잉여 속성 체크가 일어나지 않는 경우

함수 표현식에 타입 적용하기

타입스크립트에서는 함수의 매개변수부터 반환값까지를 함수 타입으로 선언하여 함수 표현식에 재사용할 수 있기 때문에 함수 표현식을 사용하는 것이 좋다.

type DiceRollFn = (sides: number) => number;
const rollDice: DiceRollFn = sides => { ... }

함수 타입의 선언은 불필요한 코드의 반복을 줄인다.

라이브러리는 공통 함수 시그니처를 타입으로 제공하기도 한다. 예를 들어 리액트는 함수 전체에 적용할 수 있는 MouseEventHandler 타입을 제공한다.

다른 함수의 시그니처를 참조하려면 typeof fn을 사용하면 된다.

타입과 인터페이스의 차이점 알기

대부분의 경우에는 타입을 사용해도 되고 인터페이스를 사용해도 된다. 그러나 이 차이를 분명하게 알고, 같은 상황에서는 동일한 방법으로 타입을 정의해 일관성을 유지하자.

인터페이스와 타입 선언의 비슷한 점

인터페이스와 타입 선언의 다른 점

interface IState {
  name: string;
  capital: string;
}

interface IState {
  population: number;
}

const dory: IState = {
  name: 'dory',
  capital: 'park',
  population: 1000
}

타입 연산과 제너릭 사용으로 반복 줄이기

타입 중복은 코드 중복만큼 많은 문제를 발생시킨다.

반복을 줄이는 간단한 방법은 타입에 이름을 붙이는 것이다. 상수를 사용해서 반복을 줄이듯이 중복된 타입에 이름을 붙여주자.

인터페이스가 다른 인터페이스를 확장하게 해서 반복을 제거할 수 있다. 이때 인터섹션 연산자(&)를 쓸 수도 있다.

interface State{
  userId: string;
  pageTitle: string;
  recentFiles: string[];
  pageContentes: string;
}

interface TopNavState {
  userId: string;
  pageTitle: string;
  recentFiles: string[];
}

다음과 같이 State의 부분집합인 TopNavState를 구현하고자 한다면 어떻게 타입 중복을 줄일 수 있을까?

type TopNavState = {
  userId: State['userId']
  pageTitle: State['pageTitle']
  recentFiles: State['recentFiles']
}

State를 인덱싱하여 속성의 타입에서 중복을 제거할 수 있다. 중복되는 코드를 더 줄여보자. 매핑된 타입을 사용하면 된다.

type TopNavState = {
  [k in 'userId' | 'pageTitle' | 'recentFiles']: State[k]
}

이런 맵핑된 타입을 사용해서 표준 라이브러리에서 Pick을 구현해 놓았다!

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

Pick은 제너릭 타입이다. 마치 함수에서 두개의 매개변수 값을 받아서 결과값을 반환하는 것처럼, Pick은 T와 K 두가지 타입을 받아서 결과 타입을 반환한다.

값의 형태를 따르는 타입을 정의해 주고 싶을 때는 typeof를 사용하면 된다. 다만 이때는 타입 정의를 먼저 하고 값이 그 타입에 할당 가능하다고 선언하는 것이 좋다.

함수에서 매개변수로 들어갈 수 있는 값을 제한하기 위해 타입 시스템을 사용하는 것처럼 제너릭 타입에서 매개변수를 제한할 수 있는 방법이 필요하다. 이때 extends를 사용한다.

type Pick<T, K extends keyof T> = {[k in K]: T[K]}

extends가 부분집합을 표현함을 다시 생각하자. 결론적으로 잘못된 키를 넣으면 오류가 발생하게 된다.

soyi47 commented 2 years ago

아이템 13. 타입과 인터페이스의 차이점 알기

아이템 14. 타입 연산과 제너릭 사용으로 반복 줄이기