유니온 타입은 타입스크립트에서 아마 가장 흔히 사용하는 타입중 하나일 것 입니다. 여러 타입을 조합하여 병합된 형태인데 특정 변수가 여러 형태의 타입을 가질 경우 유용하게 사용할 수 있다.
특히 Mapped Type을 정의할 때, key 의 타입을 유니온으로 지정하는 경우는 흔히 있는 일이다.
다만 이 유니온 타입에는 한가지 문제가 있는데, 바로 특정 변수가 특정 유니온 타입에 속하는지를 직접적으로 검증할 수 없다는 것이다.
그러나 만약 유니온이 리터럴 타입으로 구성되어 있다면 as const 를 이용하여 이 문제를 해결할 수 있다.
type Fruit = 'apple', 'banana', 'grape';
이렇게 생긴 유니온이 있다고 가정해보자.
우선 이 유니온에 속한 리터럴 타입들을 배열로 만든다. 그 후, 이 배열 뒤에 as const 를 붙여 원소들을 read-only한 상태로 만들어준다.
const fruitList = ['apple', 'banana', 'grape'] as const;
완성된 배열을 가지고 lookup type 을 이용해 유니온을 새롭게 정의할 수 있다. lookup type이 뭔지 모르겠다면 이 링크를 참고하자.
const fruitList = ['apple', 'banana', 'grape'] as const;
type Fruit = typeof fruitList[number];
이제 fruitList
를 이용하여 type guard를 구현할 수 있게되었다.
function isFruit(val: any): val is Fruit {
if (fruitList.includes(val)) return true;
return false;
}
아래와 같은 object 가 있다고 가정해보자.
const capitals = {
japan: 'tokyo',
korea: 'seoul',
china: 'beijing',
}
이 object의 value를 인수로 받는 함수를 작성하고 싶다면 어떻게 해야하는가?
const capitals = {
japan: 'tokyo',
korea: 'seoul',
china: 'beijing',
}
function goAbroad(
from: 'tokyo' | 'seoul' | 'beijing',
to: 'tokyo' | 'seoul' | 'beijing'): string {
...
}
이렇게 하나하나 적는 방법도 있지만, 우리 모두가 이 방법이 썩 만족스럽지 않다는 것을 알고있다.
여기서도 as const가 빛을 발한다.
const capitals = {
japan: 'tokyo',
korea: 'seoul',
china: 'beijing',
} as const
type Capital = typeof capitals[keyof typeof capitals]
// Capital === 'japan' | 'korea' | 'china'
function goAbroad(from: Capital, to: Capital): string {
...
}
무슨 일이 일어나고 있는지 설명을 하자면, 우선 typeof capitals는 다음과 같은 타입을 반환하게 된다.
type typeOfCapitals = typeof capitals;
// type typeOfCapitals = {
// readonly japan: "tokyo";
// readonly korea: "seoul";
// readonly china: "beijing";
// }
여기에 keyof 를 붙일 경우 다음과 같은 값을 얻을 수 있다.
type keyOfTypeOfCapitals = keyof typeof capitals;
// type keyOfTypeOfCapitals = 'japan' | 'korea' | 'china'
이제 위에서 설명한 lookup type 을 이용한 방법으로 다시 유니온을 만들면 된다.
type keyOfTypeOfCapitals = keyof typeof capitals;
type Capital = typeof Capital[keyOfTypeOfCapitals];
// Capital === 'tokyo' | 'seoul' | 'beijing'