그동안 TypeScript 프로젝트를 진행하며 느낀 점을 하나씩 정리해 보고자 해합니다.
특히 서버에서 내려주는 status 같은 “상수값”을 어떻게 관리할지에 대해 고민이 많았는데, 이걸 잘 해 두면 QA 과정에서 휴먼 에러를 크게 줄일 수 있었어서, 그것부터 한번 정리해보려고 합니다.
1. 상수 타입 정의의 필요성
- 타입 좁히기
서버에서 올 수 있는 값의 범위를 미리 제한하면
• 오타 입력
• 범위 밖 값 전달
등을 컴파일 타임에 잡아낼 수 있습니다.
// ❌ 나쁜 예: status를 string으로만 정의
type UserDetail = {
status: string
name: string
phone: string
};
- 이렇게 해 두면, 나중에 서버가
'DELETED' → 'REJECTED'
로 바뀌었을 때
모든status
사용 코드를 일일이 찾아 변경해야 하고, 누락 위험도 큽니다.
2. const
assertion + Union 타입 패턴
// 값과 타입을 한 번에 정의
export const USER_STATUS = {
ACTIVE: 'ACTIVE',
DELETED: 'DELETED',
PENDING: 'PENDING',
} as const;
// 타입 추출
export type UserStatus = (typeof USER_STATUS)[keyof typeof USER_STATUS];
- 장점
- 상수 객체 하나만 고치면,
UserStatus
를 쓴 모든 곳에 타입 에러가 발생 → 어디를 수정해야 하는지 즉시 파악 가능 - IDE 자동완성 지원
- 런타임에 남는 코드가 단순 객체이므로 디버깅도 편리
- 상수 객체 하나만 고치면,
- 단점
export type UserStatus = …
를 매번 별도 선언해야 해서 코드가 다소 길어짐
3. enum
vs. as const
// enum 사용 시
export enum USER_STATUS_ENUM {
ACTIVE = 'ACTIVE',
INACTIVE = 'INACTIVE',
}
export const USER_STATUS_LABEL = {
[USER_STATUS_ENUM.ACTIVE]: '승인',
[USER_STATUS_ENUM.INACTIVE]: '거절',
} as const;
- 장점
- 타입 선언이 따로 필요 없어서 코드가 더 깔끔
- 단점
- Numeric enum인 경우, 잘못된 숫자(예:
2
)를 넣어도 에러를 잡아주지 않음 -
enum DEVICE_STORAGE { 16G = 16, 32G = 32, } const newStorage: DEVICE_STORAGE = 99; // 에러발생이 안됨.
- (String enum은 안전하지만)
const enum
은 Babel·isolatedModules
와 호환성 이슈가 있고,
런타임 코드가 사라져 디버깅이 어려움
- Numeric enum인 경우, 잘못된 숫자(예:
4. React Hook Form · Zod와 함께 쓰기
import { z } from 'zod';
export const USER_STATUS = { ACTIVE: 'active', INACTIVE: 'inactive' } as const;
export type UserStatus = (typeof USER_STATUS)[keyof typeof USER_STATUS];
// Zod v4
export const sampleSchema = z.object({
id: z.string(),
name: z.string(),
status: z.enum(Object.values(USER_STATUS)), // 🔥 자동 추론
enumStatus: z.nativeEnum(USER_STATUS_ENUM), // enum 방식
});
z.enum()
/z.nativeEnum()
모두 타입과 런타임 값을 싱크시켜 줍니다.- 주의:
as const
를 쓰지 않으면z.enum(Object.values(...))
이string[]
으로 추론되니 꼭as const
를 함께! - 참고: zod 공식문서에서는 typescript enum사용을 권장하지 않고 있습니다. https://zod.dev/api#enum
5. 한글 vs 영문 키(key)
한글로 사용시, 위 사진처럼 자동 완성 기능도 한글로 지원 받을 수 있습니다.
export const USER_STATUS_KR = {
승인: 'ACTIVE',
거절: 'DELETED',
대기: 'PENDING',
} as const;
- 한글 키도 동일히가 사용이 가능합니다. ,
- 백엔드·다른 팀원과 소통할 때 키워드 정확도가 떨어질 수 있어서
- 대문자 영문(또는 스네이크케이스) 형태로만 쓰는 편을 추천합니다.
💡 필요 시 JSDoc 주석(
/** 승인 상태 */
)으로 한글 설명을 붙여 두면 한글 - 영문 상태 불일치로 헷갈리는 부분에서 참고가 가능합니다. (아래 사진처럼 IDE에서 미리보기가 가능합니다)
6. 정리해보면
- 가장 안전한 패턴 -> 저는 이걸로 아직 사용중입니다.
as const
+ Union 타입
- 코드가 간결해야 한다면
enum
(단, numeric enum은 피하거나, string enum만 사용)
- 호환성 이슈로 const enum은 사용 X
- 라이브러리 연동
- 휴먼 에러를 줄이는것과 더불어, React Hook Form, Zod 같은 라이브러리 연동을 통해 생산성 향상 가능.