TypeScript satisfies 사용법: 타입 지정·as const와 비교하기

2026.09.11·수정 2026.09.12·약 11분·작성: 해비·블로그 소개
먼저 확인할 내용

satisfies는 설정 객체의 구조를 검사하면서 속성별 타입 정보를 활용할 때 유용합니다. 타입 지정, as 단언, as const와 같은 객체를 비교하고, 누락된 상태를 컴파일 단계에서 찾는 예제를 다룹니다.

실습 경로: 현재 ZIP전체 코드. 먼저 설명에서 지정한 파일만 읽고, 설정·테스트 파일은 필요한 때 확인하세요.

목표·선수 지식: 객체 타입과 Record를 알고 있다면 설정의 키 누락을 검사하고 추론 차이를 설명할 수 있어야 합니다. 본문의 짧은 문법 블록은 서로 독립된 부분 예제입니다. 같은 파일에 모두 합치면 중복 선언이 생길 수 있습니다.

설정 객체에서 놓치기 쉬운 오류

게시글 상태가 임시글과 공개 두 가지라면 화면 문구도 두 상태를 빠짐없이 준비해야 합니다. 객체에 오타가 있거나 상태 하나를 빠뜨렸을 때 실행 중에 발견하는 대신, 코드를 작성할 때 검사받을 수 있습니다. 이 글의 예제는 외부 API가 아닌 코드 안에 직접 작성한 설정 객체를 대상으로 합니다.

satisfies는 TypeScript 4.9에 도입된 문법입니다. 왼쪽 값이 오른쪽 타입에 맞는지 검사합니다. 값을 변환하거나 서버 응답을 검사하는 런타임 함수는 아닙니다.

타입 지정·as·satisfies의 차이

방법 주요 목적 주의할 점
const value: Type = … 변수를 지정한 타입으로 다루기 선언한 타입의 범위로 속성을 읽음
value as Type 타입에 대한 개발자의 판단 전달 실제 값이 안전하다는 실행 시 검증은 없음
value satisfies Type 값이 타입 조건에 맞는지 검사 속성 추론은 문맥의 영향도 받음
value as const 리터럴 타입과 readonly 추론 허용된 상태가 모두 있는지는 별도 검사
type Tone = "normal" | "warning";
type Label = { text: string; color: string };
const labels: Record<Tone, Label> = {
  normal: { text: "정상", color: "gray" },
  warning: { text: "확인 필요", color: "orange" },
};

위 labels는 정상적인 코드입니다. 모든 값이 같은 Label 구조이고 추가 정보를 구분할 필요가 없다면 타입 지정만으로 충분합니다. satisfies가 항상 더 좋은 대체 문법인 것은 아닙니다.

type Tone = "normal" | "warning";
type Label = { text: string; color: string };
const labels = {
  normal: { text: "정상", color: "gray", icon: "check" },
  warning: { text: "확인 필요", color: "orange" },
} satisfies Record<Tone, Label & { icon?: string }>;
labels.normal.icon.toUpperCase();

두 번째 객체는 normal에만 icon이 있습니다. satisfies로 공통 구조를 검사하면서 normal.icon이 실제로 존재한다는 정보를 사용할 수 있습니다. 변수 전체를 Record<Tone, Label & { icon?: string }>로 지정하면 icon은 선택 속성으로 읽히므로 사용 전에 존재 여부를 확인해야 합니다.

상태 문구를 빠짐없이 관리하는 예제

type State = "draft" | "published";
type StatusInfo = { label: string; selectable: boolean };
export const statusInfo = {
  draft: { label: "임시글", selectable: true },
  published: { label: "공개", selectable: false },
} as const satisfies Record<State, StatusInfo>;

export function getStatusLabel(state: State) {
  return statusInfo[state].label;
}

Record<State, StatusInfo>는 draft와 published 키를 모두 요구합니다. 새 상태를 State에 추가했는데 설정을 추가하지 않으면 타입 오류가 발생합니다. as const는 label을 단순 string보다 구체적인 리터럴로 유지하고 속성을 읽기 전용으로 추론합니다. Object.freeze처럼 실행 중 변경을 막지는 않습니다.

React에서는 getStatusLabel(project.state) 결과를 텍스트로 렌더링하면 됩니다. 버튼 색상, 메뉴 문구, 화면 상태 안내처럼 제한된 키 집합이 있는 설정에 같은 방식을 적용할 수 있습니다.

누락·오타를 직접 확인하기

type State = "draft" | "published";
type StatusInfo = { label: string; selectable: boolean };

const missing = {
  draft: { label: "임시글", selectable: true },
} satisfies Record<State, StatusInfo>;

const typo = {
  draft: { label: "임시글", selectable: true },
  published: { label: "공개", selectable: false },
  publised: { label: "오타", selectable: false },
} satisfies Record<State, StatusInfo>;

이 블록은 오류 확인용입니다. 첫 번째 객체는 published 누락, 두 번째 객체는 publised라는 초과 키로 오류가 나야 합니다. 정상 실행 파일에 그대로 섞지 말고 따로 확인하세요. 새 객체 리터럴에서의 초과 속성 검사와, 기존 변수에 대한 구조적 타입 호환 검사는 같은 조건이 아닙니다.

리터럴 보존과 런타임 검증을 혼동하지 않기

satisfies를 붙이면 모든 문자열이 자동으로 리터럴 타입이 된다고 외우면 안 됩니다. 값이 놓인 문맥과 검사할 타입에 따라 추론 결과가 달라집니다. 수정할 수 없는 설정을 의도한다면 as const 조합을 검토하고, 변경 가능한 폼 상태라면 필요한 범위를 타입으로 명시하세요.

const config = { title: "목록" } satisfies { title: string };
config.title = "상세";

const fixed = { title: "목록" } as const satisfies { title: string };
// fixed.title = "상세"; // readonly 속성이므로 오류

Record<string, StatusInfo>는 임의의 문자열 키를 허용하므로 draft와 published가 모두 있는지 보장하지 않습니다. 필요한 키를 강제하려면 문자열 유니언을 사용합니다. fetch로 받은 JSON은 satisfies만으로 신뢰할 수 없으며 별도의 실행 시 검사가 필요합니다.

확인 과제와 적용 순서

  • State에 archived를 추가하고 타입 오류 위치를 확인합니다.
  • archived 설정을 추가한 뒤 오류가 사라지는지 확인합니다.
  • 설정 객체에서 as const를 제거하고 label의 추론 타입을 비교합니다.
  • 실행 시 보호와 타입 검사 시 보호를 구분해 설명해 봅니다.

예제는 strict 옵션으로 검사할 수 있습니다. 오류 확인용 블록을 제외한 정상 예제와, 오류가 나야 하는 예제를 분리해 확인하는 편이 좋습니다.

직접 확인하는 경계와 재현 방법

State에 archived를 추가하면 이 파일의 정상 설정도 실패합니다. 설정까지 추가하면 다시 통과해야 합니다. @ts-expect-error는 다음 줄의 오류 존재만 확인하므로 실제 오류 코드를 확인할 때는 해당 주석을 지우고 다시 검사하세요.

아래는 확인 실습의 전체 파일입니다. 빈 실습 폴더의 루트를 기준으로 표시된 경로에 모두 저장하거나 같은 내용의 ZIP을 내려받으세요.

현재 실습 ZIP

현재 본문과 같은 실습 파일 내려받기

check.ts

type State = "draft" | "published";
type Info = { label: string; selectable: boolean };
const statusInfo = {
  draft: { label: "임시글", selectable: true },
  published: { label: "공개", selectable: false },
} as const satisfies Record<State, Info>;
const literal: "임시글" = statusInfo.draft.label;
function typeChecks() {
  const missing = {
    draft: { label: "임시글", selectable: true },
  };
  // @ts-expect-error published 누락을 검출해야 합니다.
  missing satisfies Record<State, Info>;
  // @ts-expect-error 읽기 전용 속성입니다.
  statusInfo.draft.label = "변경";
  void missing;
}
void typeChecks;
if (statusInfo.published.label !== "공개") throw new Error("label mismatch");
console.log(literal, statusInfo.published.label);

tsconfig.json

{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "CommonJS",
    "outDir": "dist",
    "noEmitOnError": true,
    "types": []
  },
  "files": ["check.ts"]
}

package.json

{
  "private": true,
  "scripts": {
    "build": "tsc -p tsconfig.json",
    "start": "node dist/check.js"
  },
  "devDependencies": {
    "typescript": "7.0.2"
  }
}
npm install
npm run build
npm start

실제 확인 결과:

임시글 공개

검증 환경은 Node.js v24.19.0, TypeScript 7.0.2입니다. 설치되어 있던 의존성으로 타입 검사와 위 실행을 확인했습니다. 새 환경의 npm install, 실제 서버 응답, 브라우저 클릭·모바일 화면은 이 검증에 포함하지 않습니다.

공식 출처 확인일: 2026-09-12. typescript-4-9.html

. 완성형 뷰어와 같은 코드이며 README와 검증 기록을 포함합니다.

공식 문서와 이어서 읽을 글

이 글이 도움이 되었나요?

조회 중

TypeScript 학습 순서

필수 11개 · 전체 11개

읽음 기록 관리

전체 과정 목차 (11개)
  1. 필수 학습 · TypeScript란 무엇인가: JavaScript와 차이 정리
  2. 필수 학습 · TypeScript 기본 타입: 객체와 함수까지 strict로 익히기
  3. 필수 학습 · TypeScript 타입 좁히기: union null unknown 안전 검증
  4. 필수 길잡이 · TypeScript 실무 로드맵
  5. 필수 학습 · TypeScript as const 사용법: union 타입을 자동 생성하는 기준
  6. 필수 학습 · React TypeScript 기본 구조: tsx 파일과 props 타입 기준
  7. 필수 학습 · React TypeScript optional props 기본값 처리: undefined·null 차이
  8. 필수 학습 · TypeScript children 타입: ReactNode와 PropsWithChildren 차이
  9. 필수 학습 · TypeScript 제네릭 쉽게 이해하기: props와 API 응답 타입으로 감 잡기
  10. 필수 학습 · TypeScript 고급 상태 모델링: 판별 유니온과 never 타입 테스트
  11. 필수 학습 · TypeScript satisfies 사용법: 타입 지정·as const와 비교하기 현재 글

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기