[Effective Typescript Study] week_2

Dae-Hee·2022년 9월 6일
0

Typescript Study

목록 보기
5/11
post-thumbnail

2주차 Item 13 ~ 18


▪︎ Item 13 - 타입과 인터페이스의 차이점 알기

  • 인터페이스는 유니온 타입 같은 복잡한 타입을 확장하지 못하고 확장하고 싶다면 타입과 &를 사용해야 한다.
  type AorB 'a' | 'b' ;
  // interface 에서는 불가능

  // 별도의 다수의 타입을 하나의 변수명으로 매핑 하는 것은 가능
  type Input = { /*...*/ };
  type Output = { /*...*/ };

  interface VariableMap {
    [name: string]: Input | Output
  };

  // type 일때는
  type NamedVariable = (Input | Output) & { name: string };

  • 인터페이스는 선언 병합이 가능하다.(ES2015)
  interface A {
    name: string;
  }

  interface A {
    age: number;
  }

  const a: A = {
    name: 'jade',
    age: 29,
  }
  // 정상
  • 복잡한 타입이라면 type 사용
  • 보강의 가능성을 본다면 interface를 사용
  • 하지만 프로젝트 내부적으로 사용되는 타입에 선언 병합이 발생하는 것은 잘못된 설계
  • 중요한 것은 코드베이스의 일관성 유지

▪︎ Item 14 - 타입 연산과 제너릭 사용으로 반복 줄이기

  • 적절한 extends를 활용하여 타입의 중복을 줄인다.
  • 부분 집합으로 중복을 제거하기 위해서는 인덱싱을 활용 할 수 있다.
  • 제네릭 타입은 타입을 위한 함수와 같은 것, 제네릭 타입을 제한하려면 extends를 사용하면 된다.
  interface State = {
    userId: string;
    pageTitle: string;
    recentFiles: string;
  }

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

  // 중복 코드 제거 1 '매핑된 타입'
  type TopNavState = {
    [k in 'userId' | 'pageTitle' | 'recentFiles']: State[k]
  };

유틸리티 타입

  • Pick - 특정 타입에서 몇 개의 속성을 선택하여 타입을 정의
  type TopNavState = Pick<State, 'userId' | 'pageTitle' | 'recentFile'>;

  • Partial - 특정 타입의 부분 집합을 만족하는 타입을 정의
  interfact Options {
    a: number;
    b: number;
    c: number;
  }

  type OptionsUpdate = {[k in keyof Options]?: Options[k]};

  // keyof : 타입을 받아서 속성 타입의 유니온을 반환

  type OptionsKey = keyof Options;
  // type = "a" | "b" | "c"

  // 값의 형태에서 해당하는 타입을 정의하고 있다면 typeof 를 사용해도 된다.
  // 신중하게 사용!

  • Omit - 특정 속성만 제거한 타입을 정의
  interface Product {
    id: number;
    name: string;
    stock: number;
  }

  type shoppingItem = Omit<Product, "stock">;

  const apple: Omit<Product, "stock"> = {
    id: 1,
    name: "red apple",
  };

▪︎ Item 15 - 동적 데이터에 인덱스 시그니처 사용하기

  • 인덱스 시그니쳐는 런타임 때까지 객체의 속성을 알 수 없을 경우에만 사용한다.
  • 인덱스 시그니쳐 대신 Record를 사용 할 수 있다.
  • Record는 키 타입에 유연성을 제공하는 제너릭 타입이다.
type Vec3D = Record<'x' | 'y' | 'z', number>;
/*
Type vec3D = {
  x: number;
  y: number;
  z: number;
}
*/
      
type ABC = {[k in 'a' | 'b' | 'c']: k extends 'b' ? string : number};
/*
Type ABC = {
  a: number;
  b: string;
  c: number;
}
*/

▪︎ Item 16

  • 배열은 객체이므로 키는 숫자가 아니라 문자열이다.
  • 인덱스 시그니처로 사용된 number 타입은 버그를 잡기 위한 순수 타입스크립트 코드
  • 인덱스 시그니처에 number를 사용하기보다 Array나 튜플, 또는 ArrayLike 타입을 사용하는 것이 좋다.

▪︎ Item 17 - 변경 관련된 오류 방지를 위해 readonly 사용하기

  • readonly 접근 제어자 - 타입 단언 앞에 명시
function arraySum(arr: readonly number[]) {
  ...  
}
  
// 배열의 요소를 읽을 수 있지만, 쓸 수는 없다.
// length를 읽을 수 있지만, 바꿀 수는 없다.
// 배열을 변경하는 pop을 비롯한 다른 메서드를 호출할 수 없다.
  • readonly 타입은 기존 타입의 서브타입 이라서 변경 가능한 객체를 readonly 객체에 할당 할 수 있다.
  • 반대로 readonly 객체를 변경 가능한 객체에 할당될 수 없다.

  • readonly는 얕게 동작한다.

▪︎ Item 18 - 매핑된 타입을 사용하여 값을 동기화하기

  • 매핑된 타입을 사용해서 관련된 값과 타입을 동기화한다.

  • 인터페이스에 새로운 속성을 추가할 때, 선택을 강제하도록 매핑된 타입을 고려한다.


0개의 댓글