TypeScript 3.4 const assertion과 readonly 배열 활용

배경

회사 프로젝트를 TypeScript 3.4로 업그레이드하면서 const assertion 기능을 살펴보게 되었다. 기존에는 상수 객체나 배열을 정의할 때 타입이 넓게 추론되어 별도 타입 정의가 필요했는데, 이 부분을 개선할 수 있었다.

기존 문제

설정 객체를 다룰 때 타입 추론이 불완전했다.

const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
};
// config.apiUrl은 string으로 추론됨 (리터럴 타입 아님)

배열의 경우도 마찬가지였다.

const routes = ['home', 'about', 'contact'];
// string[]로 추론되어 구체적인 값 검증 불가

const assertion 적용

as const를 사용하면 리터럴 타입으로 좁혀진다.

const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
} as const;
// config.apiUrl은 'https://api.example.com' 타입

const routes = ['home', 'about', 'contact'] as const;
type Route = typeof routes[number]; // 'home' | 'about' | 'contact'

실제 적용 사례

API 엔드포인트 관리 코드를 리팩토링했다.

const ENDPOINTS = {
  users: '/api/users',
  posts: '/api/posts',
  comments: '/api/comments'
} as const;

type Endpoint = typeof ENDPOINTS[keyof typeof ENDPOINTS];

function fetchData(endpoint: Endpoint) {
  // 타입 안전성이 보장된 API 호출
  return fetch(endpoint);
}

fetchData(ENDPOINTS.users); // OK
fetchData('/api/wrong'); // 타입 에러

결과

  • 별도 타입 선언 없이 타입 안전성 확보
  • 설정 객체의 불변성 보장 (readonly)
  • Union 타입 자동 생성으로 코드 중복 감소

프로젝트 전반의 상수 관리 패턴을 개선할 수 있었다.

TypeScript 3.4 const assertion과 readonly 배열 활용