[이펙티브 TS] 41 - 50 정리

개발 log·2022년 4월 13일
0

TS 지식

목록 보기
14/15
post-thumbnail

41 | any의 진화를 이해하기

  • TS에서 일반적으로 변수의 타입은 변수를 선언할 때 결정된다.
  • 일반적인 타입들은 정제되지만 any는 진화한다.
  • any의 진화는 값을 할당하거나 배열에 요소를 넣은 후에만 일어난다.
  • 때문에 any타입이 진화했더라도 변수가 할당된 줄에 타입은 여전히 any이다.
  • any를 진화시키는 방식보다 명시적 타입 구문을 사용하는 것이 안전한 타입을 유지하는 방법이다.


42 | 모르는 타입의 값에는 any대신 unknown을 사용하기

interface Book {
  name: string;
  author: string;
}

function parseYAML(yaml: string): unknown {
  // ...
}

const book = parseYAML(`
    name: Wuthering Heights
    author: Emily Bronte
`);

// 에러: unknown은 사용할 수 없음
book('');
  • unknownany대신 사용할 수 있는 안전한 타입이다.

    • any는 어떠한 타입도 할당 가능하기 때문에 타입 체커가 의미가 없다.
    • 하지만 unknown은 어떠한 타입이든 unknown에 할당할 수 있지만 unknown은 오직 any에만 할당가능하기 때문에 타입시스템에서 보다 명확히 오류를 잡아낼 수 있다.
  • {}objectnullundefined를 제외한 모든 값을 포함한다.

    • 정말 nullundefined가 불가능하다고 판단되는 경우만 unknown대신 {}를 사용하라.


43 | 몽키 패치보다는 안전한 타입을 사용하기

몽키패치(Monkey Patch): 런타임 중인 프로그램 메모리의 소스 내용을 직접 바꾸는 것

몽키패치의 어원: 게릴라 패치(guerrilla patch) -> 고릴라 패치(gorilla patch) -> 원숭이 패치(monkey Patch)

  • 내장 타입에 데이터를 저장(몽키 패치)해야 하는 경우 아래와 같은 해결책이 있다.

    1. interface 보강(argmentation)
    interface Document {
      monkey: string;
    }
    
    document.monkey = 'Ta';
    1. 더 구체적인 타입 단언문
    interface MonkeyDocument extends Document {
      monkey: string;
    }
    
    (document as MonkeyDocument).monkey = 'Macaque';


44 | 타입 커버리지를 추적하여 타입 안전성 유지하기

  • noImplicitAny가 설정되어 있어도, 명시적 any 또는 서드파티 타입 선언(@types)를 통해 any타입은 코드 내에 존재할 수 있다.

  • 아래 명령어를 통해 프로젝트의 n개 심벌 중 m개가 any가 아니거나 any의 별칭이 아닌 타입을 가지고 있음을 알 수 있다.

    • npx type-coverage
    • npx type-coverage --detail


45 | devDependenciestypescript@types추가하기

  • TS를 사용할 때 전역으로 설치하기보다는 devDependencies에 추가하여 팀원들이 동일한 TS버전을 사용할 수 있도록 해야한다.
  • @types의 의존성은 devDependencies에 포함시켜야 한다.


46 | 타입 선언과 관련된 세 가지 버전 이해하기

실제 라이브러리와 타입 정보의 버전이 별도로 관리되는 방식의 문제점

  1. 라이브러리만 업데이트하고 타입 선언은 업데이트 하지않으면 타입 오류 발생
  2. 라이브러리보다 타입 선언이 최신인 경우 TS에 명시된 메서드는 최신 메서드로 표시되지만 실제 런타임에 적용되는 메서드는 이전버전의 메서드가 되어 문제 발생
  3. 프로젝트에 설치된 TS버전보다 라이브러리에서 사용된 TS버전이 더 최신인 경우 @types 선언 자체에서 타입 오류 발생
  4. 라이브러리에서 의존되는 @types의 버전이 맞지 않는 경우 문제 발생

문제가 발생하지 않기 위해 해야하는 것

  • 라이브러리를 업데이트할 때 @types도 업데이트 한다.

타입선언을 라이브러리에 포함하는 것과 DefinitelyTyped에 공개하는 것 사이의 장단점을 이해해야한다.

TS로 작성된 라이브러리라면 타입 선언을 자체적으로 포함하고,

JS로 작성도니 라이브러리라면 타입 선언을 DefinitelyTyped에 공개하는 것이 좋다.



47 | 공개 API에 등장하는 모든 타입을 익스포트하기

  • 공개 메서드에 등장한 어떤 형태의 타입이든 익스포트하는 것이 좋다.
  • 어차피 라이브러리 사용자가 추출할 수 있으므로, 익스포트하기 쉽게 만드는 것이 좋다.


48 | API주석에 TSDoc 사용하기

  • 익스포트된 함수, 클래스, 타입에 주석을 달 때는 JSDoc/TSDoc을 사용하자
  • @params, @returns 구문과 문서 서식을 위해 마크다운을 사용할 수 있다.
  • 주석에 타입 정보를 포함하면 안된다.


49 | 콜백에서 this에 대한 타입 제공하기

  • this는 동적 바인딩되는 자기 참조 변수이므로 코드를 예측하기 어렵게 한다.
  • 콜백에서 this를 사용해야 한다면, 타입 정보를 명시해야한다.


50 | 오버로딩 타입보다는 조건부 타입을 사용하기

function double<T extends number | string>(
  x: T
): T extends string ? string : number;

function double(x: any) {
  return x + x;
}
  • 오버로딩을 사용한다면 작성하기는 쉽겠지만 조건에 따라 오버로딩이 너무 많아지게 된다.
  • 때문에 조건부 타입을 사용하여 개별 타입의 유니온으로 일반화하면 타입도 더 정확하게 할 수 있다.
  • 개인적인 생각: 오버로딩을 할 경우가 그리 많지 않다면 오히려 오버로딩을 사용하는 것이 더 좋아보인다, 코드 가독성 측면에서 조건부 타입은 조금 읽기 어려운 감이 없잖아 있다.
profile
프론트엔드 개발자

0개의 댓글

관련 채용 정보