[타입시스템 18] 매핑된 타입으로 값 동기화

2022. 7. 21. 08:20책/이펙티브 타입스크립트

제목만 보면 뭔소리여 싶을 것이다. 결론부터 말하자면 안전한 객체 작성/변경을 위해 타입 체커(특히, 타입 체커가 제공하는 잉여 속성 체크)를 적극 활용하고, 매핑된 타입을 통해 반복을 줄이는 타입 선언을 하자는 뜻이다.

1. 타입 체커/잉여속성 체크

  • 앞에서도 얘기했지만 타입을 선언해두면 잉여 속성 체크 또한 가능하다
  • 즉, 프로퍼티 작성/추가/제거 과정에서 발생할 수 있는 오류를 잡아준다
  • 그리고 타입 선언 과정에서 매핑된 타입을 쓰면 반복을 줄이면서 타입 선언이 가능하다
  • 이 두가지 특성을 잘 활용하면 객체를 안전하게 작성/변경할 수 있도록 제약을 걸어둘 수 있다
  • 즉, 객체가 가질 값을 타입과 동기화할 수 있다

2. 활용
리액트로 코드를 짜고 있다고 쳐보자. x, y 좌표와 이벤트 핸들러를 props로 받아서 그림을 그리는 작업을 하려고 한다.

x, y좌표가 변경되면 재선언과 리렌더링이 일어나야 겠지만, 이벤트 핸들러는 리렌더링 된다해도 굳이 재선언될 필요가 없을 것이다. 이 상황을 어떻게 처리해야 할까? (useCallback 훅을 쓰면 되긴하겠지만 그건 제외하자)

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

    // Display
    xRange: [number, number];
    yRange: [number, number];

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


2.1 fail close 접근법 (보수적 접근법conservative)

  • 오류 발생 시 적극적으로 대처하는 방법
  • 통상 보안과 관련된 경우 적합하다
onClick 외 값들이 변경되거나 무언가 추가되면 리렌더링한다
하나하나 꼼꼼히 살펴보는 대신 리렌더링이 너무 많이 발생할 수도 있다

function shouldUpdate(oldProps :ScatterProps, newProps :ScatterProps) {
  // type k = xs | ys | xRange | yRange | onClick;
  let k :keyof ScatterProps;
  for (k in oldProps) {
      // 교체된 prop이 onClick이 아니라면 update필요
      if (k !== 'onClick') return true;
  }
  // 그게 아니라면 update 불필요
  return false;
}


2.2 fail open 접근법

  • 오류 발생 시 소극적으로 대처하는 방법
  • 기능상 큰 무리가 없고 사용성이 중요한 곳에 쓰인다
딱 필요하다고 생각되는 것만 비교하므로 간단하다
다만 진짜 리렌더링이 필요한 상황에서 누락이 발생한다면
문제는 더 커진다

function shouldUpdate(oldProps :ScatterProps, newProps :ScatterProps) {
  // x, y좌표나 그 외 값들에 변동사항이 생기면 update필요
  // onClick은 비교대상에서 제외
  return (
    oldProps.xs !== newProps.xs ||
    oldProps.ys !== newProps.ys ||
    oldProps.xRange !== newProps.xRange ||
    oldProps.yRange !== newProps.yRange
  );
}


2.3 매핑된 타입과 타입 체커 활용법

  • 위 예시에서 본 방법들은 저마다의 문제점이 있다
    - fali close : 어떤 값이 리렌더링의 기준이 되는지 알고 싶다면 함수 내부를 들여다봐야 한다
    - fail open : interface의 프로퍼티가 변경되면 필요에 따라 함수를 뜯어 고쳐야 한다(근데 만약 코드짜다 까먹으면?)
  • 이를 해결하기 위해 아래 그림과 같은 방법(즉, 매핑된 타입과 타입 체커 활용)을 사용할 수 있다

위 그림처럼 만들면 Update Criteria에서 타입체커의 잉여 속성 체크 덕분에 누락이 발생할 이유도 없고, 업데이트 함수 또한 업데이트 목록을 빠뜨릴 염려가 없어진다. 즉, 매핑된 타입으로 업데이트 목록 값을 '동기화' 한 것.