TypeScript 4.9의 satisfies 연산자로 타입 안정성 개선하기

문제 상황

프로젝트에서 설정 객체를 다루다가 타입 안정성 문제에 부딪혔다. as const를 쓰면 리터럴 타입은 보존되지만 구조 검증이 안 되고, 타입 단언을 쓰면 추론이 넓어져서 자동완성이 제대로 안 됐다.

type Colors = {
  [key: string]: string | { r: number; g: number; b: number }
};

const palette = {
  primary: '#0066cc',
  secondary: { r: 255, g: 0, b: 0 },
  danger: '#ff0000'
} as Colors;

// 타입이 string | { r: number; ... }로 넓어져서 자동완성 불가
palette.primary.toUpperCase(); // 에러

satisfies 연산자

TypeScript 4.9에서 11월에 추가된 satisfies 연산자가 이 문제를 해결해줬다.

const palette = {
  primary: '#0066cc',
  secondary: { r: 255, g: 0, b: 0 },
  danger: '#ff0000'
} satisfies Colors;

// 리터럴 타입이 유지되면서 Colors 타입도 검증됨
palette.primary.toUpperCase(); // 정상 작동
palette.secondary.r; // 정상 작동

타입을 만족하는지 검증하면서도 실제 값의 타입 추론은 그대로 유지된다. API 응답 스키마 검증이나 라우트 설정 같은 곳에서 특히 유용했다.

적용 사례

type Route = {
  path: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
};

const routes = {
  getUser: { path: '/users/:id', method: 'GET' },
  createUser: { path: '/users', method: 'POST' }
} satisfies Record<string, Route>;

// routes.getUser.method는 'GET'으로 좁혀진 타입

as const satisfies 조합도 가능해서 완전한 불변성과 타입 검증을 동시에 얻을 수 있었다. 팀원들과 공유했더니 설정 파일 작성할 때 바로 적용하더라.