TypeScript 4.8 satisfies 연산자로 타입 체크 개선하기
문제 상황
프로젝트에서 설정 객체를 다루다 보면 타입 안정성과 자동완성 사이에서 타협해야 하는 경우가 많았다. as const를 쓰면 리터럴 타입이 보존되지만, 인터페이스 준수 여부를 확인할 수 없었고, as 타입 단언을 쓰면 실제 값의 타입 추론이 사라졌다.
type ColorConfig = {
primary: string;
secondary: string;
};
// as const: 타입 체크 안 됨
const colors = {
primary: "#0000ff",
secondary: "#00ff00",
tertiary: "#ff0000" // 오타인데 에러 안 남
} as const;
// as: 타입 추론 상실
const colors2 = {
primary: "#0000ff",
secondary: "#00ff00"
} as ColorConfig;
// colors2.primary는 string으로만 추론됨
satisfies 연산자
TypeScript 4.8에서 추가된 satisfies 연산자가 이 문제를 해결했다.
const colors = {
primary: "#0000ff",
secondary: "#00ff00"
} satisfies ColorConfig;
// 1. 타입 체크 통과
// 2. 리터럴 타입 유지: colors.primary는 "#0000ff"
// 3. 잘못된 속성 추가 시 에러 발생
실무에서 가장 유용했던 케이스는 라우트 설정이었다.
type Route = {
path: string;
methods: ('GET' | 'POST' | 'PUT' | 'DELETE')[];
};
const apiRoutes = {
users: {
path: "/api/users",
methods: ["GET", "POST"]
},
posts: {
path: "/api/posts",
methods: ["GET"]
}
} satisfies Record<string, Route>;
// apiRoutes.users.methods[0]이 "GET"으로 정확히 추론됨
// 동시에 Route 타입 준수도 보장됨
결과
기존 코드베이스의 설정 객체들을 점진적으로 수정했다. 타입 안정성이 높아지면서도 IDE 자동완성이 더 정확해졌다. 특히 상수 객체를 많이 사용하는 설정 파일들에서 효과가 컸다.
TypeScript 팀이 개발자 경험을 얼마나 고민하는지 다시 한번 느꼈다.