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

문제 상황

프로젝트에서 색상 팔레트 객체를 정의할 때 타입 안전성과 자동완성을 모두 확보하는 게 까다로웠다.

const colors = {
  primary: '#0070f3',
  secondary: '#7928ca',
  danger: '#ff0000'
};

// 문제: colors.primary의 타입이 string이 아닌 리터럴 타입으로 추론되길 원함
// 하지만 Record<string, string> 타입을 명시하면 리터럴 타입 정보를 잃음

as 단언을 사용하면 타입 체크를 우회해버리고, 타입 명시를 하면 리터럴 타입 추론이 안 됐다.

satisfies 연산자

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

type ColorPalette = Record<string, string | { light: string; dark: string }>;

const colors = {
  primary: '#0070f3',
  secondary: { light: '#7928ca', dark: '#4c1d95' },
  danger: '#ff0000'
} satisfies ColorPalette;

// colors.primary는 '#0070f3' 리터럴 타입 유지
// colors.secondary.light 접근 가능 (타입 추론 정확)
// colors.wrong = 123; // 컴파일 에러

적용 사례

API 라우트 설정 객체에서도 유용했다.

type RouteConfig = Record<string, { method: 'GET' | 'POST'; auth: boolean }>;

const routes = {
  '/api/users': { method: 'GET', auth: true },
  '/api/posts': { method: 'POST', auth: true }
} satisfies RouteConfig;

// routes['/api/users'].method는 'GET' 리터럴 타입
// if (routes[key].method === 'GET') 같은 분기에서 정확한 타입 가드

정리

satisfies는 "이 값이 특정 타입을 만족하는지 검증만 하고, 타입 추론은 그대로 유지"하는 개념이다. as 단언의 위험성 없이 타입 체크를 강제할 수 있어서, 설정 객체나 상수 정의에 활용도가 높다. TypeScript 4.7 업그레이드 후 프로젝트 전반에 적용 중이다.