타입 확장은 기존 타입을 사용해서 새로운 타입을 정의하는 것을 말한다.
기본적으로 interface와 type 키워드를 사용해 타입을 정의하고 extends, 교차 타입, 유니온 타입을 사용하여 타입을 확장한다.
여기서는 타입 확장의 장점과 extends, 교차 타입, 유니온 타입간의 차이를 파악하고자 한다.
type MyUnion = A | B
interface CookingStep {
orderId: string;
price: number;
}
interface DeliveryStep {
orderId: string;
time: number;
distance: string;
}
function getDeliveryDistance(step: CookingStep | DeliveryStep) {
return step.distance;
// Property ‘distance’ does not exist on type ‘CookingStep | DeliveryStep’
// Property ‘distance’ does not exist on type ‘CookingStep’
}
type MyIntersection = A & B
interface CookingStep {
orderId: string;
time: number;
price: number;
}
interface DeliveryStep {
orderId: string;
time: number;
distance: string;
}
type BaedalProgress = CookingStep & DeliveryStep;
function logBaedalInfo(progress: BaedalProgress) {
console.log(주문 금액: ${progress.price}
);
console.log(배달 거리: ${progress.distance}
);
}
// extends 키워드를 사용해 교차 타입을 작성하였다.
interface B extends A {
// 새로운 속성을 작성한다.
}
// 유니온 타입과 교차 타입을 사용한 새로운 타입은 type 키워드로만 선언 가능하다.
type B = {
// 새로운 속성을 작성한다.
} & A
interface DeliveryTip {
tip: number;
}
interface Filter extends DeliveryTip {
tip: string;
// Interface ‘Filter’ incorrectly extends interface ‘DeliveryTip’
// Types of property ‘tip’ are incompatible
// Type ‘string’ is not assignable to type ‘number’
}
type DeliveryTip = {
tip: number;
};
type Filter = DeliveryTip & {
tip: string;
};
타입스크립트에서 타입 좁히기는 변수나 표현식의 타입 범위를 더 작은 범위로 좁혀나가는 과정을 말한다.
타입 좁히기를 통해 더 정확하고 명시적인 타입 추론을 할 수 있게 되고, 복잡한 타입을 작은 범위로 축소하여 타입 안정성을 높일 수 있다.
const replaceHyphen: (date: string | Date) => string | Date = (date) => {
if (typeof date === “string”) {
// 이 분기에서는 date의 타입이 string으로 추론된다
return date.replace(/-/g, “/”);
}
return date;
};
종종 Tagged Union으로도 불리는 식별할 수 있는 유니온은 타입 좁히기에 널리 사용되는 방식이다.
type ProductPrice = “10000” | “20000” | “5000”;
const getProductName = (productPrice: ProductPrice): string => {
if (productPrice === “10000”) return “배민상품권 1만 원”;
if (productPrice === “20000”) return “배민상품권 2만 원”;
if (productPrice === “5000”) return “배민상품권 5천 원”; // 조건 추가 필요
else {
return “배민상품권”;
}
};
type ProductPrice = “10000” | “20000” | “5000”;
const getProductName = (productPrice: ProductPrice): string => {
if (productPrice === “10000”) return “배민상품권 1만 원”;
if (productPrice === “20000”) return “배민상품권 2만 원”;
// if (productPrice === “5000”) return “배민상품권 5천 원”;
else {
exhaustiveCheck(productPrice); // Error: Argument of type ‘string’ is not assignable to parameter of type ‘never’
return “배민상품권”;
}
};
const exhaustiveCheck = (param: never) => {
throw new Error(“type error!”);
};