Among Us - Crewmates
 

[TypeScript] 24. 일관성 있는 별칭 사용하기

728x90

넓히기 과정 제어하는 방법

  1. const
    • let 대신 const로 변수를 선언하면 더 좁은 타입이 된다.
    const x = 'x';
    let vec = {x: 10, y: 20, z: 30};
    getComponent(vec, x);

    x 는 재할당 될 수 없기 때문에 ⇒ 더 좁은 타입 (”x”)로 추론할 수 있다.

타입 추론의 강도를 직접 제어하려면

⇒ 타입스크립트의 기본 동작을 재정의해야

  1. 명시적 타입 구문 제공
  1. 타입 체커에 추가적인 문맥 제공
  1. const 단언문 사용 (const 단언문과 변수 선언에 쓰이는 let 이나 const와 혼동 x)

const v1 = {
	x: 1,
	y: 2,
}; // 타입은 { x: number; y: number; }

const v2 = {
	x: 1 as const,
	y: 2,
}; // 타입은 { x: 1; y: number; }

const v3 = {
	x: 1,
	y: 2,
} as const; // 타입은 { readonly x:1, readonly y: 2; }

넓히기로 인해 오류 발생된다 생각되면, 명시적 타입 구문 또는 const 단언문을 추가하는 것을 고려해야 한다.

타입 좁히기

: 타입스크립트가 넓은 타입으로부터 좁은 타입으로 진행하는 과정

  1. null 체크
  1. 분기문 예외 throw
  1. instanceof 사용
  1. 속성체크
  1. Array.isArray 같은 일부 내장 함수
  1. 명시적 ‘태그’ 부여

    ⇒ ‘태그된 유니온’ 또는 ‘구별된 유니온’ 이라고 함

  1. 커스텀 함수 도입

    ⇒ ‘사용자 정의 타입 가드’ 라고 함

타입스크립트의 변수 ⇒ 변경

타입스크립트의 타입 ⇒ 변경 x

⇒ 때문에 일부 자바스크립트 패턴을 타입스크립트로 모델링 쉬움

⇒ 속성을 하나씩 추가보다, 여러 속성을 포함해 객체를 한번에 생성해야 ⇒ 타입 추론에 유리

const pt = {};
pt.x = 3;
pt.y = 4;
  • 자바스크립트에서는 가능
  • 타입스크립트에서는 각 할당문에 오류 발생
    // ~ '{}' 형식에 'x' 속성이 없습니다.

    Point 인터페이스 정의하면 이런 오류로 바뀜

    interface Point { x: number, y: number; }
    const pt: Point = {};
    	// ~~ '{}' 형식에 'Point' 형식의 x, y 속성이 없습니다.
    pt.x = 3;
    pt.y = 4;

    객체를 한 번에 정의하면 해결할 수 있다.

    const pt = {
    	x: 3,
    	y: 4,
    };

작은 객체들을 조합해 큰 객체를 만들어야 하는 경우 ⇒ ‘객체 전개 연산자’ 사용

{…a, …b}

별칭 사용은 주의하자

  • 남발 사용 ⇒ 제어 흐름 분석 어렵다.
interface Coordinate {
  x: number;
  y: number;
}
interface BoundingBox {
  x: [number, number];
  y: [number, number];
}
interface Polygon {
  exterior: Coordinate[];
  holes: Coordinate[][];
  bbox?: BoundingBox;
}

function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
  const box = polygon.bbox;
  if (polygon.bbox) {
    if (pt.x < box.x[0]) {
      // 객체가 'undefined'일 수 있습니다.
    }
  }
}
polygon.bbox // 타입이 BoundingBox | undefined
const box = polygon.bbox;
box // 타입이 BoundingBox | undefined

if (polygon.bbox) {
  polygon.bbox // 타입이 BoundingBox
  box // 타입이 BoundingBox | undefined
}

속성 체크는 polygon,.bbox의 타입을 정제했지만 box는 그렇지 않았기 때문에 오류가 발생했다.

이러한 오류는 "별칭은 일관성 있게 사용한다"는 기본 원칙(golden rule)을 지키면 방지할 수 있다.

타입 체커의 문제는 해결되었지만 box와 bbox는 같은 값인데 다른 이름을 사용하였다.

이는 비구조화 문법을 이용하면 간결한 문법으로 일관된 이름을 사용할 수 있다.

function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
 const {bbox} = polygon;
  if (bbox) {
    if (pt.x < bbox.x[0]) {
      // 정상, bbox 타입은 BoundingBox
    }
  }
}

주의해야할 점

별칭은 타입 체커 뿐만 아니라 런타임에도 혼동을 야기할 수 있다.

const {bbox} = polygon;
if(!bbox) {
  calculatePoygonBbox(polygon); // polygon.bbox가 채워짐
  // 이제 polygon.bbox와 bbox는 다른 값을 참조하게 됨
}

📌
요약
  • 별칭은 타입스크립트가 타입을 좁히는 것을 방해한다.
  • 따라서 변수에 별칭을 사용할 때는 일관되게 사용해야 한다.
  • 비구조화 문법을 사용해서 일관된 이름을 사용하는 것이 좋다.
  • 함수 호출이 객체 속성의 타입 정제를 무효화할 수 있다는 점을 주의해야한다.
  • 속성보다 지역 변수를 사용하면 타입 정제를 믿을 수 있다.

비동기 코드

  • 콜백 중첩 ⇒ 직관적 이해 어렵다

Uploaded by N2T

728x90
반응형