TypeScript 4.8 satisfies 연산자로 타입 안전성 개선하기

문제 상황

프로젝트에서 설정 객체를 다룰 때 타입 안전성과 자동완성을 동시에 확보하기 어려웠다. as const를 사용하면 자동완성은 되지만 타입 체크가 느슨했고, 명시적 타입 선언을 하면 리터럴 타입이 넓어져 자동완성이 제대로 동작하지 않았다.

type Colors = "red" | "green" | "blue";

// as const: 타입 체크 없음
const palette1 = {
  primary: "red",
  secondary: "yello" // 오타인데 에러 없음
} as const;

// 명시적 타입: 리터럴 타입 손실
const palette2: Record<string, Colors> = {
  primary: "red",
  secondary: "green"
};
// palette2.primary의 타입이 Colors로 넓어짐

satisfies 연산자

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

const palette = {
  primary: "red",
  secondary: "green",
  accent: "blue"
} satisfies Record<string, Colors>;

// ✅ 리터럴 타입 유지
palette.primary; // 타입: "red"

// ✅ 타입 체크 동작
const wrong = {
  primary: "yellow" // ❌ 에러 발생
} satisfies Record<string, Colors>;

실제 적용 사례

API 엔드포인트 설정에 적용했다.

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

interface ApiEndpoint {
  method: HttpMethod;
  path: string;
}

const endpoints = {
  getUser: { method: "GET", path: "/users/:id" },
  createUser: { method: "POST", path: "/users" },
  updateUser: { method: "PUT", path: "/users/:id" }
} satisfies Record<string, ApiEndpoint>;

// 자동완성과 타입 체크 모두 동작
endpoints.getUser.method; // 타입: "GET"

정리

satisfies는 타입 단언의 안전한 대안이다. 타입 체크와 타입 추론을 모두 챙길 수 있어서, 설정 객체나 상수 정의에 특히 유용했다. 팀 코드베이스에서 as const를 점진적으로 교체하는 중이다.