[CH03] Item 24 : 일관성 있는 별칭 사용하기

유지민·2023년 8월 23일
0

Effective-Typescript

목록 보기
2/5
post-thumbnail

Item 24 : 일관성 있는 별칭 사용하기

borough.location 배열에 loc 별칭(alias) 생성 예제

const borough = {name: 'Brooklyn', location: [40.688, -79.233]};
const loc = borough.location;

→ 별칭의 값 변경 시 원래 속성값에서도 변경

loc[0] = 0;
borough.location // [0, -79.233]

별칭 남발 시 제어 흐름 분석에 어려움 발생

  • 다각형을 표현하는 자료구조
interface Coordinate {
	x: number;
	y: number;
}

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

interface Polygon {
	exterior: Coordinate[];
	holes: Coordinate[][];
	bbox?: BoundingBox;
}

→ 다각형의 기하학적 구성 : exteriorholes로 구성
bbox : 최적화 속성(옵션)

function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
	if (polygon.bbox) {
	if (pt.x < polygon.bbox.x[0] || pt.x > polygon.bbox.x[1] ||
		pt.y < polygon.bbox.y[0] || pt.y > polygon.bbox.y[1]) {
	return false;
	}
}

// ...
}

: 잘 동작(타입 체커 통과), 반복되는 부분 존재
→ 중복을 줄이기 위해 임시 변수를 뽑아내는 방법

function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
	const box = polygon.bbox;	
	if (polygon.bbox) {
		if (pt.x < box.x[0] || pt.x > box.x[1] ||
		//         ~~~~~~~~           ~~~~~~~ 객체가 'undefined'일 수 있습니다.
			pt.y < box.y[0] || pt.y > box.y[1]) {
		//       ~~~~~~~~           ~~~~~~~ 객체가 'undefined'일 수 있습니다.
		return false;
	}
}

// ...
}
// strictNullChecks를 활성화했다고 가정

: 편집기에서 오류로 표시됨
polygon.bbox를 별도의 box로 별칭했고, 제어 흐름 분석을 방해했으므로

function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
   polygon.bbox // BoundingBox | undefined
   const box = polygon.bbox;
   box // BoundingBox | undefined
  if (polygon.bbox) {
      polygon.bbox // undefined 정제됨, BoundingBox 타입만 가짐
      box // undefined 정제 안됨, BoundingBox | undefined 타입 가짐
  }
}

: 오류 발생 원인 : 속성 체크는 polygon.bbox 타입 정제 O, box 타입 정제 X
별칭을 일관성 있게 사용한다는 원칙 지킬 시 방지 가능

  • Best case : 속성 체크에 box를 사용하도록 코드 변경
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
  const {bbox} = polygon;
  if (bbox) {
    const { x, y } = bbox;
	  if (pt.x < x[0] || pt.x < x[1] ||
				pt.y < y[0] || pt.y < y[1]) {
					return false;
    }
  }
	// ...
}
  • 객체 비구조화 : 보다 간결한 문법으로 일관된 이름 사용 가능
    • 유의점 1: 전체 bbox 속성이 아닌 xy가 선택적 속성일 경우 속성 체크가 더 필요 (타입 경계에 null 값 추가)
    • bbox는 선택적 속성이 적합했으나 holes는 부적합
      • holes가 선택적이라면 값이 없거나 빈 배열([])일 것
        • 차이가 없으나 이름을 구별한 것

별칭 : 타입체커 & 런타임에 혼동 야기할 수 있음

const { bbox } = polygon;
if (!bbox) {
  calculatePolygonBbox(polygon); // polygon.bbox가 채워지는 함수 
  // polygon.bbox와 bbox는 다른 값을 참조합니다.
}
  • TS - 제어 흐름 분석
    • 지역 변수에서 잘 동작!
    • 객체 속성에서는 주의!
function fn (p: Polygon) { /*...*/ }; //polygon.bbox를 제거할 가능성이 있다.

polygon.bbox // BoundingBox | undefined
if(polygon.bbox) {
  polygon.bbox // 타입이 BoundingBox
  fn(polygon); // polygon.bbox 제거할 가능성 있음
  polygon.bbox // 타입이 BoundingBox
}

함수를 호출할 때마다 속성 체크를 반복해야 하기에 좋지 않음
→ TS : 함수가 타입 정제를 무효화하지 않는다고 가정
: 실제로는 무효화될 가능성 존재

  • polygon.bbox로 사용하는 대신 bbox 지역변수로 뽑아내 사용하면 bbox 타입은 정확히 유지되나, polygon.bbox의 값과 같지 않게 유지될 수 있음

요약

  • 별칭 : 타입스크립트가 타입을 좁히는 것 방해
  • 변수에 별칭 사용 시 일관되게 사용할 것
  • 비구조화 문법을 사용해 일관된 이름 사용하는 것 권장
  • 함수 호출이 객체 속성의 타입 정제를 무효화할 수 있음에 주의
  • 속성 대신 지역변수 사용 시 타입 정제 믿을 수 있음
profile
끊임없이 도전하며 사고하는 주니어 Web 개발자 유지민입니다.

0개의 댓글