이펙티브 타입스크립트 (댄 밴더캄 지음) 를 읽고 정리
📍요약
✅오버로딩 타입보다 조건부 타입을 사용하는 것이 좋습니다.
조건부 타입은 추가적인 오버로딩없이 유니온 타입을 지원할 수 있습니다.
📍오버로딩 타입
// 함수 시그니처
function double(x: number | string): number | string; // 유니온 타입
// 함수 오버로딩
function double(x: any) {
return x + x;
}
// 매개변수가 number인데, string 이 반환되는 경우도 있을 수 있다!
const num = double(12); // string | number
const str = double('x'); // string | number
매개변수가 number인데, string 이 반환되는 경우도 있을 수 있다!
이를 제너릭으로 제어해보면
// 함수 시그니처
function double<T extends number | string>(x: T): T;
// 함수 오버로딩
function double(x: any) {
return x + x;
}
const num = double(12); // Type is 12
const str = double('x'); // Type is
console.log(str); // 출력값은 "xx", 타입은 "x"...
너무 과하게 타입을 좁혀버린다
다른 방법) 여러 가지 타입 선언으로 분리
✅타입스크립트에서 함수의 구현체는 하나지만, 타입 선언은 몇 개든지 만들 수 있다
// 타입 선언
function double(x: number): number;
function double(x: string): string;
// 함수 구현체
function double(x: any) { return x + x; }
// 원하던 결과!
const num = double(12); // Type is number
const str = double('x'); // Type is string
그런데 여기서도 에러가 존재
매개 변수 타입 범위를 조건부로 주면, 조건부 타입을 단일 타입에 할당할 수 없어 에러가 발생..
function double(x: number): number;
function double(x: string): string;
// function double(x: number|string): number|string; 이렇게 할 수도 없는 노릇..
function double(x: any) { return x + x; }
const num = double(12); // Type is number
const str = double('x'); // Type is string
function f(x: number|string) {
return double(x);
// ~ Argument of type 'string | number' is not assignable
// to parameter of type 'string'
}
잠깐 오버로딩 타입을 자세히 살펴보면,
오버로딩 타입 중에서 일치하는 타입을 찾을 때 까지 순차적으로 검색 -> string | number 타입을 string에 할당할 수 없기 때문에 에러가 발생
3번째 오버로딩 타입을 추가하는 것은 좋은 해결책은 아님..
📍조건부 타입 (conditional type)
✅타입 공간에서의 if 구문과 같다
function double<T extends number | string>(x: T): T extends string ? string : number;
function double(x: any) { return x + x; }
// 예제들이 모두 정상!
const num = double(12); // number
const str = double('x'); // string
// function f(x: string | number): string | number
function f(x: number|string) {
return double(x);
}
예제들이 정상 작동한다