[이펙티브 타입스크립트] 아이템32 ~ 아이템33

Yongwoo Cho·2022년 6월 6일
0

TIL

목록 보기
83/98
post-thumbnail

[아이템32] 유니온의 인터페이스보다는 인터페이스의 유니온을 사용하기

interface Layer {
  layout: FillLayout | LineLayout | Pointlayout;
  paint: FillPaint | LinePaint | PointPaint;
}

layout이 LineLayout 타입이면서 paint 속성이 FillPaint 타입인 것은 말이 되지 않는다. 이런 조합을 허용하면 오류가 발생하기 쉽고 인터페이스를 다루기가 어렵다.

interface FillLayer {
  layout: FillLayout;
  paint: FillPaint;
}
interface LineLayer {
  layout: LineLayout;
  paint: LinePaint;
}
interface PointLayer {
  layout: PointLayout;
  paint: PointPaint;
}

type layer = FillLayer | LineLayer | PointLayer;

이런 형태로 Layer을 정의하면 layout과 paint 속성이 잘못된 조합으로 섞이는 경우를 방지할 수 있다.

interface Person {
  name: string;
  // 둘 다 동시에 있거나 동시에 없음
  placeOfBirth?: string;
  dateOfBirth?: Date;
}

👍 더 좋은 설계방법

interface Person {
  name: string;
  birth?: {
    place: string;
    date: Date;
  };
}

유니온의 인터페이스보다 인터페이스의 유니온이 더 정확하고 타입스크립트가 이해하기도 좋다

[아이템33] string 타입보다 더 구체적인 타입 사용하기

string 타입의 범위는 매우 넓기 때문에 string 타입으로 변수를 선언하려 한다면, 혹시 그보다 더 좁은 타입이 적절하지는 않을지 검토해 봐야 한다.

👎 string 타입이 남발된 코드

interface Album {
  artist: string;
  title: string;
  releaseDate: string; // YYYY-MM-DD
  recordingType: string; // "live" 또는 "studio"
}

타입 체커를 통과 하더라도 releaseDate에 'August 17th, 1959' 같은 다른 날짜 형식, recordingType에 Live와 같은 대문자오타, 매개변수의 순서 오류가 발생할 수 있다.

✔️ 타입의 범위를 좁혀 개선한 코드

type RecordingType = "studio" | "live";
interface Album {
  artist: string;
  title: string;
  releaseDate: Date;
  recordingType: RecordingType;
}

👍 장점

  • 타입을 명시적으로 정의함으로써 다른 곳으로 값이 전달되어도 타입 정보가 유지된다.
  • 타입을 명시적으로 정의하고 해당 타입의 의미를 설명하는 주석을 붙여 넣을 수 있다.
  • keyof 연산자로 더욱 세밀하게 객체의 속성 체크가 가능해진다.

✔️ 객체의 속성 이름을 함수 매개변수로 받을 때는 string보다 keyof T를 사용하는 것이 좋다

  • 개선 전
function pluck(records: any[], key: string): any[] {
  return records.map((r) => r[key]);
}

function pluck<T>(records: T[], key: keyof T): T[keyof T][] {
  return records.map((r) => r[key]);
}

pluck(albums, "releaseDate"); // type: (string | Date)[] 👎 적절한 타입이 아님
  • 개선 후
function pluck<T, K extends keyof T>(records: T[], key: K): T[K][] {
  return records.map((r) => r[key]);
}

pluck(albums, "artist"); // type : string[]
pluck(albums, "releaseDate"); // type: Date[] 👍 적절한 타입
profile
Frontend 개발자입니다 😎

0개의 댓글