이펙티브 타입스크립트 아이템 19 ~ 37

이수빈·2025년 6월 11일
0

Typescript

목록 보기
19/20
post-thumbnail

item 19. 추론가능한 타입을 사용해 장황한 코드 방지하기

  • 타입스크립트가 타입을 추론 할 수 있다면 => 타입을 작성하지 않는게 좋다.
  • 추론될 수 있는경우라도 => 객체리터럴과 함수반환에는 타입명시를 고려해야한다.
const furby: Product = {
   name: 'Furby',
   id: 630509430963,
// ~~ Type 'number' is not assignable to type 'string'
   price: 35,
};
logProduct(furby);
// 직접적으로 오류 잡아줌

const cache: {[ticker: string]: number} = {};
function getQuote(ticker: string): Promise<number> {
  if (ticker in cache) {
    return cache[ticker];
    // ~~~ Type 'number' is not assignable to type 'Promise<number>'
  }
  // ...
}

item 22. 타입 좁히기

  • 타입 좁히는 방법 : 일반적으로 코드문맥에서 조건문으로 타입가드를 한다.

  • 그렇지만 조건문으로 narrowing을 할 수 없는 상황이라면? 다른 방법을 고려해본다.

  • 태그기법 => type이라는 태그를 통해 좁혀준다.

interface UploadEvent { type: 'upload'; filename: string; contents: string }
interface DownloadEvent { type: 'download'; filename: string; }
type AppEvent = UploadEvent | DownloadEvent;

function handleEvent(e: AppEvent) {
  switch (e.type) {
    case 'download':
      console.log('Download', e.filename);
      //                      ^? (parameter) e: DownloadEvent
      break;
    case 'upload':
      console.log('Upload', e.filename, e.contents.length, 'bytes');
      //                    ^? (parameter) e: UploadEvent
      break;
  }
}
  • 타입 단언 함수 도입(사용자 정의 타입 가드)

  • 반환값이 true인경우 => type을 HTMLInputElement로 좁힌다.

function isInputElement(el: Element): el is HTMLInputElement {
  return 'value' in el;
}

function getElementContent(el: HTMLElement) {
  if (isInputElement(el)) {
    return el.value;
    //     ^? (parameter) el: HTMLInputElement
  }
  return el.textContent;
  //     ^? (parameter) el: HTMLElement
}

item 26. 타입추론에 문맥이 어떻게 사용되는지 이해하기

  • 아래와 같은 함수가 있다고 가정
// Parameter is a (latitude, longitude) pair.
function panTo(where: [number, number]) { /* ... */ }

panTo([10, 20]);  // OK

const loc = [10, 20];
//    ^? const loc: number[]
panTo(loc);
//    ~~~ Argument of type 'number[]' is not assignable to
//        parameter of type '[number, number]

const loc = [10, 20] as const;
//    ^? const loc: readonly [10, 20]
panTo(loc);
//    ~~~ The type 'readonly [10, 20]' is 'readonly'
//        and cannot be assigned to the mutable type '[number, number]'
  • 두가지 case모두 문제발생 => 첫번째는 number[]형으로 너무 넓어서, 두번째는 너무 좁아서 발생한다. readonly가 아니라서.

  • 가장 좋은 해결책은 => panTo의 파라미터에 readonly를 추가하는 것. 근데 안된다면?

function panTo(where: readonly [number, number]) { /* ... */ }
const loc = [10, 20] as const;
panTo(loc);  // OK
  • as const의 단점 => 타입정의에 실수가 있다면 오류는 타입정의가 아니라 호출되는 곳에서 발생함.
const loc = [10, 20, 30] as const;  // error is really here.
panTo(loc);
//    ~~~ Argument of type 'readonly [10, 20, 30]' is not assignable to
//        parameter of type 'readonly [number, number]'
//          Source has 3 element(s) but target allows only 2.

item 30. 문서에 타입 정보 쓰지 않기

  • 주석과 변수명에 타입정보를 적는 것은 피하자.
  • 특정 파라미터의 타입을 설명하고 싶다면 JSDocs의 @params 구문을 사용하면 된다.

item32. 유니온의 인터페이스 보다는 인터페이스의 유니온을 사용하기

interface Layer {
  layout: FillLayout | LineLayout | PointLayout;
  paint: FillPaint | LinePaint | PointPaint;
} 

// xxxxxx

interface FillLayer {
  layout: FillLayout;
  paint: FillPaint;
}
interface LineLayer {
  layout: LineLayout;
  paint: LinePaint;
}
interface PointLayer {
  layout: PointLayout;
  paint: PointPaint;
}
type Layer = FillLayer | LineLayer | PointLayer;
// oo
profile
응애 나 애기 개발자

0개의 댓글