TypeScript 5.6 satisfies 연산자와 타입 안전성 개선

배경

프로젝트에서 API 응답 타입을 정의할 때 타입 안전성과 자동완성을 모두 확보하기 어려웠다. as const를 쓰면 리터럴 타입은 보존되지만 타입 체크가 약해지고, 명시적 타입 선언을 하면 추론이 넓어지는 문제가 있었다.

TypeScript 5.6에서 satisfies 연산자의 개선사항을 확인하고 실무에 적용해봤다.

기존 방식의 문제

// 방법 1: 타입 추론은 좋지만 체크 약함
const config = {
  endpoint: '/api/users',
  method: 'GET'
} as const;

// 방법 2: 타입 체크는 되지만 추론 손실
const config: ApiConfig = {
  endpoint: '/api/users',
  method: 'GET'
}; // method는 string으로 widening

satisfies 활용

type ApiConfig = {
  endpoint: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  timeout?: number;
};

const config = {
  endpoint: '/api/users',
  method: 'GET',
  timeout: 5000
} satisfies ApiConfig;

// method는 'GET' 리터럴 타입 유지
// 동시에 ApiConfig 준수 여부 체크됨

타입 체크와 정확한 타입 추론을 동시에 얻을 수 있었다. 특히 대규모 설정 객체나 라우트 정의에서 유용했다.

실전 적용: 라우트 설정

type Route = {
  path: string;
  component: string;
  auth: boolean;
};

const routes = {
  home: { path: '/', component: 'Home', auth: false },
  dashboard: { path: '/dashboard', component: 'Dashboard', auth: true }
} satisfies Record<string, Route>;

// routes.home.path는 '/' 리터럴
// 오타 발생 시 컴파일 에러

결론

satisfies는 as const와 타입 어노테이션의 장점을 결합한다. 기존 코드베이스의 설정 객체들을 점진적으로 전환하고 있다. 타입 안전성이 필요한 상수 정의에 기본 패턴으로 사용할 예정이다.