본문 바로가기

공부

[이펙티브 타입스크립트] 6장 타입 선언과 @types

[ 아이템 48 ] API 주석에 TSDoc 사용하기 

함수의 앞부분에 주석이 있으면 함수가 어떤 기능을 하는지 쉽게 알 수는 있는데 사용자를 위한 문서라면 JSDoc 스타일의 주석으로 만드는 것이 좋습니다.

JSDoc 스타일의 주석은 툴팁으로 표시가 가능하며, @param @returns 같은 일반적 규칙도 사용할 수 있습니다. 

타입스크립트 언어 서비스가 JSDoc 스타일을 지원하기 때문에 적극적으로 활용하는 것이 좋습니다. 

타입스크립트 관점에서는 TSDoc이라고 부르기도 합니다.

 

 

[ 아이템 49 ] 콜백에서 this에 대한 타입 제공하기

자바스크립트에서 this는 매우 혼란스러운 기능입니다. let이나 const로 선언된 변수가 렉시컬 스코프(lexical scope)인 반면, this는 다이나믹 스코프(dynamic scope)입니다.

다이나믹 스코프의 값은 정의된 방식이 아니라 호출 방식에 따라 달라집니다.

첫 번째 obj.sayName()은 호출했을 때 obj를 알고 있기에 name은 hyeon이 됩니다. 반면 name() 함수는 호출했을 때 obj를 모르기 때문에 '' 값이 나옵니다. 

 

function addKeyListener(
    el: HTMLElement,
    fn: (this: HTMLElement, e: KeyboardEvent) => void
) {
    el.addEventListener('keydown', e =>{
        fn.call(el, e); // 정상
        fn(el, e); // 오류, 'this' 컨텍스트를 메서드의 'HTMLElement' 형식 'this'
    });
}

콜백 함수의 매개변수에 this를 추가하면 this 바인딩이 체크되기 때문에 실수를 방지할 수 있습니다. 

콜백 함수에서 this 값을 사용해야 한다면 this는 API의 일부가 되는 것이기 때문에 반드시 타입 선언에 포함해야 합니다. 

 

요약

  • this 바인딩이 동작하는 원리를 이해해야 합니다.
  • 콜백 함수에서 this를 사용해야 한다면, 타입 정보를 명시해야 합니다. 

[ 아이템 50 ] 오버로딩 타입보다는 조건부 타입을 사용하기 

 

double 함수에는 string 또는 number 타입의 매개변수가 들어올 수 있습니다. 그러므로 유니온 타입을 추가했습니다.

다음은 타입스크립트 함수 오버로딩 개념을 사용한 예제입니다.

function double(x: number | string): number | string;
function double(x: any) { return x + x; }

하지만 이렇게 유니온 타입으로 묶어버리면 다음과 같이 타입이 애매한 상황이 생기게 됩니다.

number 타입을 인자로 주었는데 반환된 타입이 number 또는 string 이 됩니다. 

const num = double(12); // string | number

또다른 방법으로 제네릭 을 사용하는 것이 있을 수 있습니다.

 

하지만 이 방법은 타입이 너무 과하게 구체적입니다. 

function double<T extends string | number>(x: T): T 
function double(x: any) { return x + x; }

const num = double(12);  // 12
const str = double('x'); // 'x'

또 다른 방법은 여러 가지 타입 선언으로 분리하는 것입니다. 

타입스크립트에서 함수의 구현체는 하나지만, 타입 선언은 몇 개든지 만들 수 있습니다.

이 방법에도 여전히 버그가 존재하는데 유니온 타입에서 문제가 발생합니다.

function double(x: number): number;
function double(x: string): string;
function double(x: any) { return x + x; }

const num = double(12);  // number
const str = double('x'); // string

function f(x: number | string) {
    return double(x) // ~ 'string | number' 형식의 인수는  
                          'string' 형식의 매개변수에 할당될 수 없습니다.
}

세 번째 오버로딩(string | number)을 추가하여 문제를 해결할 수 도 있지만, 가장 좋은 해결책은 조건부 타입을 사용하는 것입니다.

function double<T extends number | string>(
  x: T
): T extends string ? string : number;
function double(x: any) { return x + x; }

이 코드는 제너릭을 사용했던 예제와 유사하지만, 반환 타입이 더 정교합니다. 

  • T가 string의 부분 집합이면(string, 또는 문자열 리터럴, 또는 문자열 리터럴 유니온), 반환 타입이 string입니다. 
  • 그 외의 경우에는 반환 타입이 number 입니다. 

오버로딩이 필요한 경우에 가끔 조건부 타입이 필요한 상황이 발생합니다. 오버로딩 타입을 작성 중이라면 조건부 타입을 사용해서 개선할 수 있을 지를 검토해 보는 것이 좋습니다. 

 

요약 

  •  오버로딩 타입보다 조건부 타입을 사용하는 것이 좋습니다.

'공부' 카테고리의 다른 글

Kafka 도커로 구축  (0) 2023.03.19
[이펙티브 타입스크립트] 4장 타입 설계  (0) 2022.05.01
[이펙티브 타입스크립트] 3장 타입 추론  (0) 2022.04.13