Book Review/Effective Typescript

day5_EffectiveTypescript 스터디

예 강 2023. 6. 16. 09:08

2022년 11월 30일 글입니다.

Item18. 매핑된 타입을 사용하여 값을 동기화하기

요약 1: 매핑된 타입을 사용해서 관련된 값과 타입을 동기화 하도록 한다.

  • 값을 그대로 때려박는것 보다, 매핑된 타입을 사용하면 함수가 변경되었을 때 참조하고 있던 다른코드에서 알아서 오류를 발생시키기 때문에 유지보수에 용이하다.
  • 프로젝트를 유지보수 할 때 우리는 함수를 변경해야 할 때가 많다. 이럴 때 변경된 값을 바로바로 찾을 수 있도록 매핑된 타입을 이용하여 값을 동기화 하자.
  • 그러면 함수가 변경되었을 경우 타입체커가 알아서 오류를 발생시켜줘서 유지보수에 용이하다.

예를 들어 산점도를 그리는 인터페이스가 있고 필요할 때만 데이터를 그리기 위해 핸드러를 정의했다고 하자.
interface ScatterProps {
  xs: number[];
  ys: number[];

  xRange: [number, number];
  yRange: [number, number];
  color: string;

  onClick: (x: number, y: number, index: number) => void;
}

function shouldUpdate(oldProps: ScatterProps, newProps: ScatterProps) {
  let k: keyof ScatterProps;
  for (k in oldProps) {
    console.log(k);
    if (oldProps[k] !== newProps[k]) {
      //같지 않으면 차트를 다시그린다.
      if (k !== "onClick") return true;
    }
  }
}

위와같이 차트가 변경될 때마다 전부 새로 그리는 로직을 보수적 (conservative) 접근법 이자 실패에 닫힌(fail close)

function shouldUpdate(oldProps: ScatterProps, newProps: ScatterProps) {
  return (
    oldProps.xs !== newProps.xs ||
    oldProps.ys !== newProps.ys ||
    oldProps.xRange !== newProps.xRange ||
    oldProps.yRange !== newProps.yRange ||
    oldProps.color !== newProps.color
    // (no check for onClick)
  );
}

위 코드는 실패에 열린 접근법이라고 한다. 실제로 산점도 전체를 다시 그려야 하는 경우가 있을 수도 있어서 이것도 최적화 코드라고 하기엔 무리가 있다.

그럼 우리는 어떻게 해야할까?

새로운 속성이 추가될 때 직접 shouldUpdate 를 고치게 하는데 이를 타입체커가 알려주게 동기화 해보자 !

interface ScatterProps {
  xs: number[];
  ys: number[];

  xRange: [number, number];
  yRange: [number, number];
  color: string;

  onClick: (x: number, y: number, index: number) => void;
}

const REQUIRES_UPDATE: { [k in keyof ScatterProps]: boolean } = {
  xs: true,
  ys: true,

  xRange: true,
  yRange: true,
  color: true,
  onClick: false,
};

function shouldUpdate(oldProps: ScatterProps, newProps: ScatterProps) {
  let k: keyof ScatterProps;
  for (k in oldProps) {
    if (oldProps[k] !== newProps[k] && REQUIRES_UPDATE) {
      return true;
    }
  }
  return false;
}

필요할 때 산점도를 다시 그리게 하는 한편 k 값이 REQUIRES_UPDATE와 다를때 오류가 발생하도록 동기화 시켰다.

이를 위해 REQUIRES_UPDATE가 선언됐으며 만약 데이터 또는 디스플레이 속성이 변경되었을때 이벤트핸들러를 짜고 이와 같은 구조를 사용하는 REQUIRES_UPDATE로 오류를 내도록 동기화 하면, 새로운 속성이 추가됐을 때마다 직접 shouldUpdate함수를 수정하기 용이하다.

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