Effective Typescript (Day 6)

d_fe·2022년 11월 30일
post-thumbnail

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

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

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

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

위 코드가 필요할 때에만 차트를 다시 그릴 수 있도록 최적화 할 수 있다.
data나 display 속성이 변경되면 다시 그려야 하지만, 이벤트 핸들러가 변경되면 다시 그릴 필요가 없다.
❗이런 최적화는 리액트에서 일반적이며, 렌더링할 때마다 이벤트 핸들러 Prop이 새 화살표 함수로 설정된다. (useCallback 훅, 렌더링할 때마다 새 함수를 생성하지 않도록 하는 또 다른 기법)


➡️ 최적화 첫 번째 방법

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

    return false;
}

만약 새로운 속성이 추가되면 위 함수는 값이 변경될 때마다 차트를 다시 그릴 것이다.
이런 처리를 '보수적 접근법' 또는 '실패에 닫힌 접근법' 이라 한다.
이 접근법을 이용하면 차트가 정확하지만 너무 자주 그려질 가능성이 있다.

보수적 접근법
실패에 닫힌 접근법은 오류 발생 시 적극적으로 대처하는 방향이며, 반대로 열린 접근법은 소극적으로 대처하는 방향을 말한다.
(예를 들어, 만약 보안과 관련된 곳이라면 실패에 닫힌 방법을 써야 할 것이고, 기능에 무리가 없고 사용성이 중요한 곳이라면 실패에 열린 방법을 써야 할 것.)


➡️ 최적화 두 번째 방법

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)
}

최적화 1의 차트를 불필요하게 다시 그리는 단점을 해결했으나, 실제로 차트를 다시 그려야 할 경우에 누락되는 일이 생길 수 있다.


앞의 두 가지 최적화 방법은 모두 이상적이지 않다.

타입 체커가 동작할 수 있게 하는 것이 좋다.

const REQUIRES_UPDATE : {[k in keyof ScatterProps]: boolean} = {
  						// 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[k]) {
          // 위 조건식은 REQUIRES_UPDATE의 onClick을 false로 설정해놨기 때문에
          // onClick에 대해선 통과하지 않는다.
            return true;
        }
    }

    return false;
}

매핑된 타입과 객체를 사용하는 것이 핵심이다.
이렇게 사용하면 ScatterProps 인터페이스에 속성이 추가/삭제/변경된다면 REQUIRES_UPDATE의 정의에 오류가 발생할 것을 정확히 잡아낼 것이다.

✔️ 매핑된 타입은 한 객체가 또 다른 객체와 정확히 같은 속성을 가지게 할 때 이상적이다.
예제처럼 매핑된 타입을 사용해 TS가 코드에 제약을 강제하도록 할 수 있다.

profile
오늘보다 내일 더 성장하는 프론트엔드 개발자가 되기 위해

0개의 댓글