TypeScript satisfies 연산자, 언제 써야 할까
TypeScript 4.9에서 추가된 satisfies 연산자는 “이 값이 어떤 타입을 만족하는지 검사는 하되, 추론된 구체적인 타입은 유지하고 싶다” 라는 요구를 해결합니다.
문제: 타입 주석을 쓰면 정보가 사라진다
type Theme = Record<string, string | number[]>;
const theme: Theme = {
primary: '#2563eb',
spacing: [4, 8, 16],
};
theme.spacing.map((v) => v * 2);
// ❌ 'string | number[]' 형식에 'map' 속성이 없습니다.
theme을 Theme으로 선언하는 순간 각 속성이 string | number[]로 넓어집니다. 분명 spacing은 배열인데, 쓸 때마다 좁혀 줘야 합니다.
문제: as 단언은 검사를 건너뛴다
const theme = {
primary: '#2563eb',
spacing: [4, 8, 16],
// 오타가 있어도 통과됨
radius: undefined,
} as Theme;
as는 “믿어 달라”는 뜻이라, 실제로 타입에 맞지 않는 값이 들어가도 잡아주지 못합니다.
해결: satisfies
const theme = {
primary: '#2563eb',
spacing: [4, 8, 16],
} satisfies Theme;
theme.spacing.map((v) => v * 2); // ✅ number[]로 추론됨
theme.primary.toUpperCase(); // ✅ string으로 추론됨
Theme에 맞지 않으면 컴파일 에러가 납니다.- 그러면서
theme의 타입은 리터럴 그대로{ primary: string; spacing: number[] }로 유지됩니다.
실전 활용 예
1. 설정 객체
const routes = {
home: '/',
post: (slug: string) => `/posts/${slug}`,
} satisfies Record<string, string | ((...args: never[]) => string)>;
routes.post('hello'); // ✅ 함수로 호출 가능
2. 유니온 키를 빠짐없이 채우기
type Status = 'idle' | 'loading' | 'error';
const label = {
idle: '대기',
loading: '불러오는 중',
error: '오류',
} satisfies Record<Status, string>;
// Status에 값이 추가되면 여기서 바로 에러가 나서 누락을 막아 줍니다.
3. 상수 배열과 as const 조합
const TAGS = ['Astro', 'SEO', 'TypeScript'] as const satisfies readonly string[];
type Tag = (typeof TAGS)[number]; // 'Astro' | 'SEO' | 'TypeScript'
정리
| 방법 | 타입 검사 | 추론 정보 유지 |
|---|---|---|
const x: T = ... |
✅ | ❌ (T로 넓어짐) |
... as T |
❌ (단언) | ❌ |
... satisfies T |
✅ | ✅ |
“형태는 검사하고 싶지만 값의 구체적인 타입은 그대로 쓰고 싶다”면 satisfies가 정답입니다.
댓글