공부

[TS] 이펙티브 타입스크립트 #14

jaeeedev 2023. 2. 26. 18:07

타입 일부만 재사용하기

보통은 원본 타입에 타입을 확장하여 재사용하지만 전체-부분 관계일 때는 인덱싱을 해서 전체 타입 중 일부만 가져오는게 더 맥락에 맞다.

인덱싱하는 방법

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

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

매핑된 타입 사용

  [k in "userId" | "pageTitle" | "recentFiles"]: State[k];

이렇게 하면 더 짧아진다. 표준 라이브러리에서 Pick 이라는 이름으로 제공중

type TopNavState = Pick<State, "userId" | "pageTitle" | "recentFiles">;

타입 전체를 선택적 속성으로 만들기

keyof와 매핑된 타입 사용

interface Options {
  width: number;
  height: number;
  color: string;
  label: string;
};

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

class UIWidget {
  constructor(init: Options) {}
  update(options: OptionsUpdate) {}
}

Partial 사용

interface Options {
  width: number;
  height: number;
  color: string;
  label: string;
};

class UIWidget {
  constructor(init: Options) {}
  update(options: Partial<Options>) {}
}

값에서 타입 뽑기

const INIT_OPTIONS = {
  width: 640,
  height: 480,
  color: "#00FF00",
  label: "VGA",
};

type initOptions = typeof INIT_OPTIONS;

자바스크립트가 아닌 타입스크립트 단계에서 연산되고 더 정확하게 타입을 표현.

반환된 값에 타입 명명하기

ReturnType 제네릭 사용

function getUserInfo(userId: string) {
  // 코드

  return { userId, name, age, height, weight, favoriteColor };
}

type UserInfo = ReturnType<typeof getUserInfo>;

ReturnType<typeof getUserInfo> 인것을 명심하기

제네릭 타입은 타입을 위한 함수다.
제네릭 타입에서 매개변수를 제한할 방법이 필요하다. -> extends 를 사용한다.

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

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

const couple1: DancingDuo<Name> = [
  { first: "Fred", last: "Astaire" },
  { first: "Ginger", last: "Rogers" },
];

const couple2: DancingDuo<{ first: string }> = [
  { first: "Sonny" },
  { first: "Cher" },
]; // Name을 충족하지 않아 오류 발생

extends 활용하기

type Pick1<T, K> = { [k in K]: T[k] };
// Type 'K' is not assignable to type 'string | number | symbol'.

K에 들어갈 수 있는 타입 범위가 넓어서 문제 발생 -> 범위를 좁혀 주어야

K는 인덱스로 사용될 수 있는 타입(string, number, symbol) 이어야 하고 T의 키의 부분집합이어야 함(keyof T)

// 해결된 코드
type Pick2<T, K extends keyof T> = {
  [k in K]: T[k];
};
type FirstLast = Pick2<Name, "first" | "last">;
type FirstMiddle = Pick2<Name, "first" | "middle">;

// Type '"first" | "middle"' does not satisfy the constraint 'keyof Name'.

범위를 잘 지정하여 잘못된 키가 들어올 경우 오류 발생