[타입추론 24] 일관성 있는 별칭(alias)

2022. 7. 23. 16:32책/이펙티브 타입스크립트

별칭의 남발은 코드의 가독성을 매우 저하시킨다. 뿐만 아니라 TS의 타입 좁히기를 어렵게 만들기도 하며, 비순수함수와 섞일 경우 코드 자체가 안돌아가는 상황까지 발생한다. 따라서 일관된 별칭을 만들고 일관되게 사용하는 것이 바람직하다.

말만 들으면 그래서 어쩔? 싶을테니 다각형의 구조를 파악하는 예시를 통해 위 내용을 한번 살펴보자.

interface Coordinate {
  x :number;
  y :number;
}

interface Boundary {
  x :[number, number];
  y :[number, number];
}

interface Polygon {
  exterior :Coordinate[];
  holes :Coordinate[][];
  boundary? :Boundary;
}

 

1. 이상한 별칭

이상한 별칭을 사용함으로써 발생하는 직관적인 문제는 코드의 가독성을 저하시킨다는 것이다.

function isInPolygon(pt :Coordinate, polygon :Polygon) {
  const box = polygon.boundary;
  // boundary라고 이름지어놓고 
  // 보는사람 헷갈리게 box라는 지역변수를 왜 굳이 만들었을까?
}

function isInPolygon(pt :Coordinate, polygon :Polygon) {
  const { boundary } = polygon;
  // 디스트럭처링 문법으로 뽑아내는게 훨씬 일관성있고
  // 코드를 이해하기도 쉽다
}

 

2. type narrowing 방해

별칭을 만들었으면 일관되게 사용해야 한다는 뜻을 알아보자. 아래는 디스트럭처링 할당으로 별칭을 잘 만들어놓고서도 일관되게 사용하지 않아 타입 좁히기를 방해한 예시이다.

function isInPolygon(pt :Coordinate, polygon :Polygon) {
  const { boundary } = polygon; // Boundary | undefined
  if (polygon.boundary) {
    if (pt.x < boundary.x[0] || pt.x > boundary.x[1] || pt.y < boundary.y[0] || pt.y > boundary.y[1])
    // TypeError: Object is possibly 'undefined'
    // polygon.boundary는 타입을 좁혀놨지만 
    // 따로 만든 boundary는 타입을 좁혀준 적이 없다 
    // polygon.boundary :Boundary
    // boundary :Boundary | undefined
  }
}

 

3. 비순수함수

비순수함수와 엮이게될 경우, 일관된 별칭을 사용하고 있더라도 원본 값이 바뀌면서 제어 흐름 자체가 이상해질 수 있다.

function calPolygon(polygon :Polygon) {
  polygon = '원본 폴리곤을 변형시키는 무언가';
  return;
}

function isInPolygon(pt :Coordinate, polygon :Polygon) {
  const { boundary } = polygon; // Boundary | undefined
  if (polygon.boundary) {
    calPolygon(polygon);
    // 이제부터 boundary와 polygon.boundary는 다른 값이 된다
  }
}