본문 바로가기

TypeScript

우아한 타입 스크립트 with 리액트 / 4장 타입 확장하기, 좁히기

타입 확장하기

타입 확장은 기존 타입을 사용해서 새로운 타입을 정의하는 것을 말한다.

기본적으로 타입스크립트에서는 interface와 type 키워드를 사용해서 타입을 정의하고,

extends, 교차 타입, 유니온 타입을 사용하여 타입을 확장한다.

 

타입 확장의 장점

타입 확장의 가장 큰 장점은 코드 중복을 줄일 수 있다는 것이다.

코드를 작성하다 보면 중복되는 타입 선언이 생기기 마련인데, 이때 중복되는 타입을

반복 선언하는 것보다 기존에 작성한 타입을 바탕으로 타입 확장을 함으로써

불필요한 코드 중복을 줄일 수 있다.

interface Item {
  name: string;
  img: string;
}

interface CartItem extends Item {
  quantity: number;
}

 

위 예시에서 CartItem은 Item에 있는 모든 요소가 필요해 속성을 중복해서 작성하지

않고 확장을 활용하여 타입을 정의했다.

 

interface 키워드 대신 type을 쓴다면 아래와 같이 작성하면 된다.

type Item = {
  name: string;
  img: string;
};

type CartItem = {
  quantity: number;
} & Item;

 

타입 확장은 또한 확장성이란 장점을 가지고 있다.

위의 Item을 활용하면 요구사항이 늘어날 때마다 새로운 CartItem 타입을 확장하여

정의할 수 있다.

type EventCartItem = {
  orderable: boolean;
} & CartItem;

 

유니온 타입

유니온 타입은 2개 이상의 타입을 조합하여 사용하는 방법이다.

집합 관점으로 보면 합집합으로 해석할 수 있다.

type MyUnion = A | B;

 

MyUnion은 A와 B의 합집합이므로 A 타입과 B 타입의 모든 값이 MyUnion 타입의

값이 된다. 주의해야 할 점은 유니온 타입으로 선언된 값은 유니온 타입에 포함된

모든 타입이 공통으로 갖고 있는 속성에만 접근할 수 있다.

 

교차 타입

교차 타입도 기존 타입을 합쳐 필요한 모든 기능을 가진 하나의 타입을 만드는 것으로

이해할 수 있다.

interface CookingStep {
  orderId: number;
  time: number;
  price: number;
}

interface DeliveryStep {
  orderId: string;
  time: number;
  distance: string;
}

type Progress = CookingStep & DeliveryStep;

 

여기서 유니온 타입과 다른 점은 위의 Progress는 CookingStep과 DeliveyStep

타입을 합쳐 모든 속성을 가진 단일 타입이 된다는 점이다.

 

교차 타입은 교집합의 개념과 비슷하다.

타입스크립트의 타입을 속성의 집합이 아닌 값의 집합으로 이해해야 한다.
Progress 교차 타입은 CookingStep이 가진 속성(orderId, time, price)

DeliveryStep이 가진 속성(orderId, time, distance)을 모두 만족(교집합)하는 값의 타입(집합)이라고 해석할 수 있다.

interface DeliveryTip {
  tip: string;
}

interface StarRating {
  rate: number;
}

type Filter = DeliveryTip & StarRating;

const filter: Filter = {
  tip: "1000원 이하",
  rate: 4,
};

 

교차 타입을 사용할 때 서로 호환되지 않는 경우도 있다.

type A = string | number;
type B = number | boolean;

type C = A & B;

 

교차타입은 두 타입을 동시에 만족하는 타입을 생성하므로 C는 number타입이 된다.

 

extends와 교차 타입

extends 키워드를 사용해서 교차 타입을 작성할 수도 있다.

interface Item {
  name: string;
  img: string;
}

interface CartItem extends Item {
  quantity: number;
}

 

CartItem은 Item을 확장함으로써 Item의 속성을 모두 포함하고 있다.

즉, CartItem은 Item의 속성을 모두 포함하는 상위 집합이 되고 Item은 부분집합이 된다.

이를 교차 타입의 관점에서 작성하면 다음과 같다.

type Item = {
  name: string;
  img: string;
};

type CartItem = {
  quantity: number;
} & Item;

const cartItem: CartItem = {
  name: "가방",
  img: "가방.png",
  quantity: 1,
};

 

유니온 타입과 교차 타입을 사용한 새로운 타입은 오직 type 키워드로만 선언할 수 있다.

 

extends 키워드를 사용한 타입이 교차 타입과 100% 상응하지는 않는다.

type A = {
  id: string;
};

type B = A & {
  id: number;
};

 

다음과 같은 경우에 id는 never 타입을 갖게 된다.

 

타입 좁히기 - 타입 가드

타입스크립트에서 타입 좁히기는 변수 또는 표현식의 타입 범위를 더 작은 범위로 좁혀나가는

과정을 말한다. 타입 좁히기를 통해 더 정확하고 명시적인 타입 추론을 할 수 있게 되고,

복잡한 타입을 작은 범위로 축소하여 타입 안정성을 높일 수 있다.