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

문제 상황

프로젝트에서 API 엔드포인트를 상수로 관리하는데, as const를 사용하면 타입이 너무 좁아지고, 그냥 선언하면 타입 체크가 느슨해지는 문제가 있었다.

const routes = {
  users: '/api/users',
  posts: '/api/posts',
  invalid: '/api/wrong' // 오타가 있어도 감지 못함
} as const;

type Route = typeof routes[keyof typeof routes];

satisfies 연산자 도입

TypeScript 5.0의 satisfies를 사용하니 타입 제약을 검증하면서도 원본 타입을 유지할 수 있었다.

type ApiRoute = `/api/${string}`;

const routes = {
  users: '/api/users',
  posts: '/api/posts',
  comments: '/api/comments'
} satisfies Record<string, ApiRoute>;

// 타입 추론 유지되어 자동완성 동작
const userRoute = routes.users; // string 타입

실무 적용 케이스

특히 설정 객체나 테마 정의에서 유용했다.

type ColorScheme = {
  primary: string;
  secondary: string;
  background: string;
};

const theme = {
  primary: '#3b82f6',
  secondary: '#8b5cf6',
  background: '#ffffff',
  // accent: '#000' // 누락 시 에러 발생
} satisfies ColorScheme;

// theme.primary는 string으로 추론됨

as const와 달리 리터럴 타입으로 좁혀지지 않아서, 동적으로 값을 할당해야 하는 경우에 더 유연했다.

결론

타입 안전성과 추론의 균형을 맞추는 데 satisfies가 적절했다. 기존 코드베이스의 설정 객체들을 점진적으로 마이그레이션하고 있다.