[Effective Typescript - 아이템 32] 유니온의 인터페이스보단 인터페이스의 유니온을 사용하기

Song·2022년 1월 19일
0

1. 유니온의 인터페이스 VS 인터페이스의 유니온

1-1. 유니온의 인터페이스 🤔

하나의 인터페이스안에서 값의 타입을 유니온으로 사용하는 것

interface Layer {
    /** 모형의 shape */
    layout: FillLayout | LineLayout | PointLayout;
    /** 모형의 스타일 */
    paint: FillPaint | LinePaint | PointPaint;
}

Layer라는 인터페이스안에 한개 이상의 layout과 paint의 속성이 존재한다.
이 때,layout이 직선이고 paint가 fill이라면 오류가 발생하는 상황이지만
현재 유니온의 인터페이스 방식으로는 속성 간의 관계가 명확하지 않기 때문에 미리 오류를 방지하기 어렵다.

1-2. 인터페이스의 유니온 👍

태그된 유니온을 이용하여 속성 간의 관계를 명확하게 만들었다.

태그된 유니온 (Tagged Union) 이란
상황에 따라 인터페이스를 분리한 후 해당 인터페이스들을 type을 이용하여 유니온으로 사용한 것
태그type에 주어진 개별 속성이며 런타임 시 타입의 범위를 줄일 수 있도록 도와준다

type Layer = FillLayer | LineLayer | PointLayer;

interface FillLayer {
    layout: FillLayout;
    paint: FillPaint;
}

interface LineLayer {
    layout: LineLayout;
    paint: LinePaint;
}

interface PointLayer {
    layout: PointLayout;
    paint: PointPaint;
}

Layer type에 세개의 인터페이스가 세부화되어 유니언으로 명시되었다.
이러한 방법은 아이템 28(비행기 조종, 기장 사고 방지)에서도 지향했던 방식과 동일한 맥락인데
속성이 잘못된 조합으로 섞이는 경우를 방지하고 유효한 상태만을 표현할 수 있도록 되어있다.

2. 태그된 유니온을 이용한 예제

2-1. 분기별 처리가 필요할 때

type Layer = FillLayer | LineLayer 

interface FillLayer {
    kind: 'Fill';	// 태그
    layout: FillLayout;
    paint: FillPaint;
}

interface LineLayer {
    kind: 'Line';      // 태그
    layout: LineLayout;
    paint: LinePaint;
}

function drawLayer(layer: Layer) {
   if (layer.kind === 'fill') {	// 태그를 이용하여 분기 처리
       const { layout, paint } = layer // 타입은 FillLayout, FillPaint    
   } else if (layer.kind ==== 'Line') {
       const { layout, paint } = layer // 타입은 LineLayout, LinePaint    
   }
}

단점: 코드가 어수선해 보일 수 있다.

2-2. 선택적 필드가 동시에 값이 있거나 동시에 undefined인 경우

Bad 👎

첫번째 시도
- 주석으로만 설명되어 있으므로 오류날 가능성이 있다.
interface Person {
   name: string;
   // 아래 값은 둘 다 있거나 둘 다 없습니다.
   placeOfBirth?: string;
   dateOfBirth?: Date;
}

Good 👍

두번째 시도
- birth 에서 place만 있고 date가 없을 경우 오류가 난다.
interface Person {
   name: string;
   birth?: {
      place: string;	// place마
      date: Date;
   }
}

2-3. 타입의 구조를 손 댈 수 없는 상황일 때

interface name {
   name: string;
   // 아래 값은 둘 다 있거나 둘 다 없습니다.
   placeOfBirth?: string;
   dateOfBirth?: Date;
}

왜냐하면 type 속성은 타입스크립트에서 태그로 쓰이며 런타임 시 타입스크립트가 타입을 판단할 때 도움을 주기 때문에 유용, 잘 어울림

특징

  • 정확성 향상
  • 관계를 잘 나타냄
  • 타입 체커와 잘 맞음

3. 결론

  1. 인터페이스 구현 시 속성간의 관계를 분명, 세부화하게 나타내자
  2. 태그된 유니온은 런타임 타입 체커와 잘 맞기 때문에 필요 시 사용하자
  3. 각 타입의 속성들 간 관계를 제대로 모델링하면 코드의 정확성 업, 오류 다운
profile
Learn From Yesterday, Live Today, Hope for Tomorrow

0개의 댓글