TypeScript 5.4 satisfies 연산자로 타입 안전성 높이기

문제 상황

라우트 설정 객체를 정의하는 과정에서 타입 안전성과 자동완성을 모두 확보하기 어려웠다. as const를 쓰면 타입 추론은 정확하지만 구조 검증이 없고, 타입 단언을 쓰면 런타임 에러 가능성이 있었다.

// 기존 방식 - 타입 체크 없음
const routes = {
  home: '/home',
  users: '/users',
  profile: '/profile'
} as const;

// 또는 타입 단언 - 오타 검증 안됨
const routes: Record<string, string> = {
  home: '/home',
  users: '/usres', // 오타 발견 못함
};

satisfies 연산자 활용

TypeScript 4.9부터 사용 가능한 satisfies를 적용했다. 타입 체크를 수행하면서도 정확한 타입 추론을 유지한다.

type Route = Record<string, `/${string}`>;

const routes = {
  home: '/home',
  users: '/users',
  profile: '/profile'
} satisfies Route;

// 타입 추론 정확하게 유지
type HomeRoute = typeof routes.home; // '/home'

// 타입 위반 시 컴파일 에러
const invalid = {
  home: 'home' // Error: Type 'string' does not satisfy...
} satisfies Route;

API 응답 타입에 적용

API 응답 객체에도 유용했다. 인터페이스 준수를 강제하면서 리터럴 타입도 보존된다.

interface ApiResponse {
  status: 'success' | 'error';
  code: number;
  data?: unknown;
}

const response = {
  status: 'success',
  code: 200,
  data: { userId: 123 }
} satisfies ApiResponse;

// 'success' 리터럴 타입 유지
if (response.status === 'success') {
  // 정확한 분기 처리
}

결론

satisfies는 타입 단언보다 안전하고 타입 추론도 유지하는 우아한 방법이다. 설정 객체, 상수 정의, API 스펙 검증 등에서 유용하게 사용 중이다.