typescript) 문자열 배열의 원소들의 값을 Union type으로 가지는 type 생성하기

내가 겪은 케이스는 다음과 같다.

const transportations = ["taxi", "bus", "subway", "bicycle", "walk"];

위와 같이 상수로 사용할 교통 수단의 경우의 수를 미리 정의해 놓을 수 있다.

그리고, 파티의 참석자 정보를 객체로 표현한다고 했을 때, 아래와 같은 데이터를 상정할 수 있다.

const participant = {
  nickname: "park";
  age: 43;
  transportation: "airplane";
}

위의 객체의 타입을 interface로 표현하면, 다음과 같을 것이다.

interface Participant {
  nickname: string;
  age: number;
  transportation: string;
}

물론, 이대로도 훌륭하지만 transportation는 string이다.

transportation는 단순히 string인가?

아니다.

우리는 미리 정해둔 교통수단들이 있고, transportation는 미리 정해둔 교통수단 외의 것. 예를 들면 위의 예의 airplane과 같은 문자열이 할당될 수 없다.

 

때문에 다음과 같이 수정할 수 있을 것이다.

type Transportation = "taxi", "bus", "subway", "bicycle", "walk";

interface Participant {
  nickname: string;
  age: number;
  transportation: Transportation;
}

이제 airplane은 할당할 수 없게 타입스크립트가 오류를 내뱉어 줄 것이다.

 

하지만, 내 문제의식은 여기서 시작된다.

만약 새로운 교통 수단이 추가된다고 생각해보자.

metro는 배열과 union type에 각각 추가되어야 한다.

실상 배열과 type은 동일한 문자열들을 가지고 있어야 하는데도 말이다.

 

그렇다면, 문자열 배열의 원소들 중 하나를 가질 수 있는 union type을 배열로 부터 생성할 수 있지 않을까?

난 많은 검색과 테스트를 통해서 이를 실제로 구현할 수 있는 방법을 찾아내었다!

const transportation = ["taxi", "bus", "subway", "bicycle", "walk", "airplane"] as const;

type Transportation = typeof transportation[number];

interface Participant {
  nickname: string;
  age: number;
  transportation: Transportation;
}

const test: Participant = {
  nickname: "pp",
  age: 123,
  transportation: "airplane"
}

이제 타입은 기존에 선언된 배열로부터 생성된다.

단순히 상수를 선언한 배열에 원하는 교통수단을 추가하면, 자동으로 타입이 생성되며 다른 수정 없이 타입스크립트의 기능을 사용할 수 있다.