TypeScript as const로 상수 배열에서 union 타입을 어떻게 만드나요?
as const는 상수 값의 구체적인 literal 타입을 보존하고 객체·배열을 readonly 형태로 추론하도록 합니다. 상수 배열에서 허용 값의 union을 만들면 값 목록과 타입 목록을 따로 관리하지 않아도 됩니다.
직접 확인: 오류에서 수정까지
TypeScript as const 사용법: union 타입을 자동 생성하는 기준 · 독립 실습
얻을 결과: as const와 typeof FILTERS[number]를 이용해 값과 타입을 한곳에서 유지합니다.
예제 크게 보기 (새 탭)단독 검사는 tsconfig.json이 없는 새 폴더에서 example.ts 한 파일씩 교체하며 진행합니다. TypeScript가 없다면 설치 글에서 Node.js/npm·TypeScript 준비를 확인하세요. 타입 검사 성공은 코드 실행 성공과 구분합니다.
독자 질문: 필터 배열의 값에서 ‘all’ | ‘done’ 타입을 자동으로 얻으려면?
얻을 결과: as const와 typeof FILTERS[number]를 이용해 값과 타입을 한곳에서 유지합니다.
오류 코드를 별도 example.ts에 복사합니다.
const FILTERS = ['all', 'done'] as const;
type Filter = typeof FILTERS[number];
const current: Filter = 'pending';
예상 타입 오류 (TS2322): ‘pending’은 ‘all’ | ‘done’에 속하지 않습니다. 목록의 실제 값으로 수정합니다.
위 코드를 다음 수정 예제로 교체합니다.
const FILTERS = ['all', 'done'] as const;
type Filter = typeof FILTERS[number];
const current: Filter = 'done';
console.log(current);
npx tsc --strict --noEmit example.ts
확인 결과: TypeScript 7.0.2의 별도 최소 예제에서 오류 TS2322, 수정 후 exit 0 확인. TaskFlow 전체 체크포인트·브라우저 실행은 미확인.
다음 학습: 09회차에서 satisfies로 설정 객체의 키와 값 형태를 검사합니다.
literal widening
let status =
'active';
let은 변경 가능하므로 status는 string으로 추론됩니다.
const:
const status =
'active';
더 좁은 literal 타입을 유지할 수 있습니다.
객체 property는 const 객체여도 변경 가능하므로 넓게 추론될 수 있습니다.
const config = {
mode: 'light',
};
mode는 일반적으로 string으로 추론될 수 있습니다.
as const
const config = {
mode: 'light',
} as const;
mode는 ‘light’ literal로 보존되고 property가 readonly가 됩니다.
상수 배열
const filters = [
'all',
'active',
'completed',
] as const;
filters는 readonly tuple로 추론됩니다.
타입 추출:
type TaskFilter =
typeof filters[number];
결과:
'all' | 'active' | 'completed'
값 목록과 타입 union을 따로 유지할 필요가 없습니다.
객체 값 union
const statusCode = {
idle: 0,
loading: 1,
success: 2,
} as const;
type StatusCode =
typeof statusCode[
keyof typeof statusCode
];
결과는 0 | 1 | 2입니다.
readonly 주의
as const는 객체와 배열을 readonly로 좁게 만듭니다.
const filters = [
'all',
'active',
] as const;
다음 변경은 허용되지 않습니다.
filters.push(
'completed',
);
실제로 변경해야 하는 배열이라면 as const가 목적에 맞지 않을 수 있습니다.
as const는 runtime freeze가 아닙니다
TypeScript의 readonly는 컴파일 단계의 제약입니다.
Object.freeze와 같은 runtime 불변 처리와 동일한 개념으로 설명하면 안 됩니다.
독립 예제
const roles = [
'admin',
'member',
'guest',
] as const;
type Role =
typeof roles[number];
function isRole(
value: string,
): value is Role {
return roles.some(
(role) =>
role === value,
);
}
값 목록과 타입 목록이 하나의 source에 연결됩니다.
자주 하는 실수
모든 객체에 as const
수정 가능한 객체까지 readonly가 되므로 실제 목적을 확인합니다.
as const를 runtime validation으로 오해
외부 문자열이 union에 속하는지는 runtime에서 별도 확인해야 합니다.
학습 완료 체크리스트
- literal widening을 설명할 수 있습니다.
- as const로 literal을 보존할 수 있습니다.
- readonly tuple에서 union 타입을 추출할 수 있습니다.
- as const가 runtime freeze가 아님을 이해했습니다.
- 변경 가능한 데이터에는 무조건 as const를 쓰지 않을 수 있습니다.
작은 변형으로 확인하기
FILTERS에 pending을 추가하면 current: Filter = ‘pending’이 통과합니다. as const를 뺀 뒤 임의 문자열이 허용되는 차이를 확인하세요.
선택 실습: 할 일 앱에 적용하기
TaskFlow는 작업을 추가·완료·삭제하는 할 일 앱입니다. 이 선택 실습에서는 JavaScript 코드를 TypeScript로 확장합니다.
TaskFilter의 실제 옵션 배열과 타입을 하나의 source로 통합합니다.
선택: 연재 프로젝트와 전체 자료
연재 프로젝트를 이어 만드는 분을 위한 자료입니다. 이 글의 개념과 예제만 찾으셨다면 필요한 파일과 실행 방법만 펼쳐보세요.
TaskFlow 프로젝트 적용
TypeScript as const 사용법: union 타입을 자동 생성하는 기준 · 단계별 TaskFlow
타입을 적용한 TaskFlow에서 작업을 추가·완료 전환·삭제하세요. 타입만 바뀐 단계는 이전과 화면이 같습니다.
예제 크게 보기 (새 탭)변경 설명과 부분 예제를 읽은 뒤, 시작·완료 파일과 적용 순서에서 필요한 선언·import·화면 연결을 포함한 전체 파일을 확인하세요. 이번 단계의 변경 이유와 적용 위치도 함께 확인합니다.
시작본과 이번 변경
TypeScript keyof typeof 인덱스 접근 타입 사용법의 완료 체크포인트를 기준으로 이어갑니다. 변경하지 않는 파일은 그 시작 상태를 유지합니다.
src/constants/task.ts의 옵션 배열에 as const를 적용하고 TaskFilter를 typeof TASK_FILTERS[number]로 통합합니다. 이전 수동 union의 import가 새 선언을 가리키는지 검사합니다.
이전 체크포인트
typescript-step-07-keyof-typeof
이번 목표
TaskFilter의 실제 옵션 배열과 타입을 하나의 source로 통합합니다.
전체 파일·코드 보기
src/constants/task.ts
export const TASK_FILTERS = [
'all',
'active',
'completed',
] as const;
export type TaskFilter =
typeof TASK_FILTERS[number];
export const TASK_FILTER_LABELS:
Record<
TaskFilter,
string
> = {
all: '전체',
active: '진행 중',
completed: '완료',
};
Record는 12회차에서 자세히 설명하지만 여기서는 모든 filter key에 label이 있어야 한다는 목적만 이해합니다.
Before / After
Before
filter 배열
filter union
서로 따로 관리
After
TASK_FILTERS
→ TaskFilter 자동 파생
검증
npx tsc --noEmit
중간부터 시작하는 전체 파일과 적용 순서
시작 ZIP은 직전 프로젝트 단계 typescript-step-07-keyof-typeof의 실제 완료 파일입니다. 프로젝트 순서를 이어가는 기준이며 사이트의 기술 읽기 순서와는 구분합니다.
- 시작 ZIP을 새 폴더에 풉니다. 이 폴더가 작업 루트이며 기존 체크포인트 파일을 별도로 찾을 필요가 없습니다.
- 상수 배열을 as const로 고정하고 TaskFilter를 배열에서 파생합니다. 기존 types/task.ts의 필터 타입은 재내보내기로 단일화합니다.
- 아래 변경 파일을 같은 상대 경로에 추가하거나 전체 교체합니다. 표시하지 않은 파일과 images는 시작본 그대로 유지합니다. package-lock.json은 완료 ZIP에 있는 파일을 함께 적용합니다.
- 작업 루트에서 명령을 실행하고 예상 결과를 확인합니다. 완료 ZIP은 직접 적용한 결과를 비교하는 기준입니다.
추가·교체 파일
CHANGES.md— 전체 교체README.md— 전체 교체src/types/task.ts— 전체 교체src/constants/task.ts— 전체 교체
실행과 확인
npm ci
npm run dev
npm run typecheck
npm test
npm run build
개발 서버는 실행 상태로 두고 다른 터미널에서 검사 명령을 실행하세요. Node.js 24.18.0에서 검증했습니다. JavaScript는 http://127.0.0.1:4173, TypeScript는 Vite 실행 출력의 주소로 접속합니다.
예상 결과: all·active·completed만 허용하며 목록과 유니온이 하나의 선언에서 파생됩니다.
실제 검증: TypeScript strict 검사·긍정/부정 타입 계약·런타임 검사·Vite 빌드 통과. 시작 ZIP에 이 글의 변경 파일만 적용한 결과와 완료 ZIP의 모든 파일 내용이 일치했습니다. 브라우저 화면 배치·실제 기기·외부 CDN 가용성은 이 검사에 포함하지 않았습니다.
이 절의 전체 파일은 ZIP과 일치합니다. 위쪽 원문의 짧은 예제나 생략 표시가 있는 부분 코드는 개념·변경 위치 설명용입니다. 서버 저장과 인증은 제공하지 않으며 JSON fixture는 로컬 읽기 실습용입니다.
복사할 변경 파일 전체 코드
src/types/task.ts — 전체 파일
export type Task = {
id: string;
title: string;
completed: boolean;
};
export type { TaskFilter } from '../constants/task.js';
src/constants/task.ts — 전체 파일
export const TASK_FILTERS = [
'all',
'active',
'completed',
] as const;
export type TaskFilter =
typeof TASK_FILTERS[number];
export const TASK_FILTER_LABELS:
Record<
TaskFilter,
string
> = {
all: '전체',
active: '진행 중',
completed: '완료',
};
완료 체크포인트
typescript-step-08-as-const
다음 학습
다음 글에서는 객체가 타입 조건을 만족하는지 검사하면서도 구체적인 타입 추론을 보존하는 satisfies를 배웁니다.
다음 글: TypeScript satisfies 사용법: 타입 지정·as const와 비교하기
글 소개·학습 준비·전체 목차

TypeScript · 8 / 22 · 필수 학습 · as const
TypeScript는 일반적으로 변할 수 있는 값의 타입을 넓게 추론합니다.
as const를 사용하면 값의 literal 타입을 보존하고 객체와 배열을 readonly 형태로 좁게 추론할 수 있습니다.
이 패턴은 상수 배열에서 union 타입을 자동 생성할 때 특히 유용합니다.
이번 글에서 배우는 내용
- literal widening
- as const
- readonly tuple
- 배열 값에서 union 추출
- 객체 값 보존
- as const를 남용하지 않는 기준
단독 학습 선수 지식
keyof·typeof·배열 인덱스 접근 타입을 알면 됩니다. 이전 TaskFlow 파일 없이 직접 확인 예제로 학습할 수 있습니다.
목차
이 글이 도움이 되었나요?
읽음 기록
읽음 — / 전체 22개 · 필수 21개
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.