1. TypeScript satisfies 연산자란?
TypeScript 4.9에서 도입된 satisfie 연산자는 객체가 특정 타입을 만족하는지 검증하면서도, 값의 원래 타입을 유지할 수 있도록 도와주는 연산자입니다. 기존에는 as를 사용하여 타입을 변환했지만, 이 방법은 타입을 너무 넓게 만들거나 불필요한 타입 오류를 발생시키는 문제가 있었습니다. satisfies를 사용하면 타입 안정성을 높이면서도 더 정밀한 타입 추론을 할 수 있습니다.
2. satisfies 연산자로 해결할 수 있는 문제
2.1 타입을 만족하면서도 세밀한 타입 추론 유지
기존에는 객체의 타입을 만족시키기 위해 as를 사용했지만, 이 방법은 값의 타입을 넓게 만들어 불필요한 타입 오류를 발생시키곤 했습니다.
❌ as를 사용할 경우 타입이 넓어짐
type Status = "success" | "error" | "loading";
const response = {
status: "success",
data: { message: "Operation completed" },
} as { status: Status; data: { message: string } };
function handleStatus(status: "success" | "error") {
if (status === "success") {
console.log("Success!");
} else {
console.log("Error!");
}
}
// ❌ TypeScript가 "loading"도 가능하다고 판단하여 타입 에러 발생!
handleStatus(response.status); // Argument of type 'Status' is not assignable to parameter of type '"success" | "error"'.
Type '"loading"' is not assignable to type '"success" | "error"'.
✅ satisfies를 사용하면 타입이 좁게 유지됨
const response = {
status: "success",
data: { message: "Operation completed" },
} satisfies { status: Status; data: { message: string } };
handleStatus(response.status); // ✅ 정확한 타입 추론이 이루어져 타입 에러 없음
✔️ satisfies를 사용하면 response.status가 "success"로 유지되므로, handleStatus 함수에서 "loading"을 받을 가능성이 사라집니다.
2.2 잘못된 키 추가 방지 (객체의 키를 제한하는 경우)
❌ as를 사용하면 잘못된 키 추가 시 오류 감지 불가능
type ButtonVariant = "primary" | "secondary" | "danger";
const buttonStyles = {
primary: { color: "blue", text: "Click me" },
secondary: { color: "gray", text: "Cancel" },
danger: { color: "red", text: "Delete" },
warning: { color: "yellow", text: "Caution" }, // ❌ 타입 오류 감지되지 않음
} as Record<ButtonVariant, { color: string; text: string }>;
✅ satisfies를 사용하여 잘못된 키 감지 가능
type ButtonVariant = "primary" | "secondary" | "danger";
const buttonStyles = {
primary: { color: "blue", text: "Click me" },
secondary: { color: "gray", text: "Cancel" },
danger: { color: "red", text: "Delete" },
// ✅ satisfies를 사용하여 잘못된 키 사용 감지
warning: { color: "yellow", text: "Caution" }, // Object literal may only specify known properties, and 'warning' does not exist in type 'Record<ButtonVariant, { color: string; text: string; }>'.
} satisfies Record<ButtonVariant, { color: string; text: string }>;
✔️ satisfies를 사용하면 잘못된 키(예: "warning")가 추가될 경우 즉시 타입 에러가 발생합니다.
3. satisfies를 활용해야 하는 경우 비교
구분 | as | satisfies | 비고 |
타입 단언 (Type Assertion) | 타입을 강제로 지정하며, 실제 타입 검사를 수행하지 않음 | 타입을 만족하는지 체크하며, 원래 타입을 유지 | 타입을 만족하는지 확인하면서도 원래 타입을 유지해야 할 때 |
넓은 타입 → 좁은 타입 변환 | 가능하나, 타입 검증 없이 단언 | 타입을 만족하는지 체크하여 안전한 변환 가능 | 특정 구조를 만족하는지 확인하면서 변환해야 할 때 |
객체 리터럴 타입 체크 | 타입 검사를 수행하지 않음 | 객체 리터럴 타입 검사를 수행 | 객체 리터럴을 강제할 때 |
잉여 속성 검사 | 우회 가능 (경고 무시) | 잉여 속성 검사 적용 | 잉여 속성을 방지하면서 타입을 강제할 때 |
추론 보존 여부 | 강제된 타입으로 변경됨 | 원래 타입 유지 가능 | 타입 추론을 유지하면서도 타입 검증이 필요할 때 |
4. 결론
as를 사용하면 as는 타입 강제하기 때문에 타입이 넓어지거나, 잘못된 값이 허용되는 문제가 발생할 수 있습니다. satisfies는 객체의 타입을 검증하면서도, 값을 최대한 좁게 유지하여 타입 안정성을 높이는 데 도움을 줍니다.
즉, satisfies를 사용하면 기존 as보다 타입 안정성이 훨씬 좋아지고, 잘못된 키 추가나 불필요한 타입 확장을 방지할 수 있습니다.
개발을 하시다 잉여 속성을 방지하면서 특정 타입을 만족해야 하는 경우 as나 복잡한 타입으로 해결해야 한다면 satisfies로 해결할 수 있는 문제일 수도 있습니다.