Template Literal Types로 문자열 규칙을 타입으로 고정해보면, 곧 다음 단계의 요구가 자연스럽게 등장합니다. “이 문자열 키들을 사람이 직접 만들지 않고, 객체 정의로부터 자동으로 만들 수는 없을까?”라는 질문입니다.
실무에서는 다음과 같은 상황을 자주 마주합니다.
- 설정 객체와 문자열 키 목록이 따로 관리된다
- 설정은 추가됐는데, 키 타입은 업데이트되지 않았다
- 권한/설정/피처 플래그 키가 점점 관리 불가능해진다
이 문제의 핵심은 “중복 정의”입니다. 이번 글에서는 Mapped Types와 Conditional Types를 조합해, 단 하나의 설정 정의로부터 문자열 키 규칙을 자동 생성하는 패턴을 실무 기준으로 정리합니다.
개념/배경 설명: 중복 정의는 왜 반드시 어긋나는가
다음 구조는 실무에서 매우 흔합니다.
// 설정 객체
const featureConfig = {
user: {
enabled: true,
},
order: {
enabled: false,
},
};
그리고 어딘가에는 이런 타입이 존재합니다.
type FeatureKey =
| 'user.enabled'
| 'order.enabled';
이 구조는 처음에는 명확하지만, 설정이 늘어날수록 반드시 어긋납니다. 문제는 사람이 실수해서가 아니라, 중복이 구조적으로 허용되었기 때문입니다.
핵심 설계 1: Mapped Types로 객체 구조를 순회한다
첫 번째 단계는 “객체의 키 구조를 타입 레벨에서 순회하는 것”입니다.
type Keys<T> = {
[K in keyof T]: K;
}[keyof T];
이 패턴은 단순하지만 매우 중요합니다. 객체의 모든 키를 타입 유니언으로 바꾸는 기본 도구입니다.
실무 포인트 정리
- Mapped Types는 “순회”의 역할이다
- 객체 구조를 타입으로 그대로 가져온다
- 수동 나열을 제거하는 출발점이다
핵심 설계 2: Conditional Types로 중첩 여부를 판단한다
설정 객체는 보통 중첩 구조를 가집니다. 이때 필요한 것이 Conditional Types입니다.
type IsObject<T> =
T extends Record<string, any>
? true
: false;
이 조건을 이용해, “여기서 멈출지, 더 내려갈지”를 판단할 수 있습니다.
핵심 설계 3: Template Literal Types로 키를 조합한다
이제 앞에서 배운 Template Literal Types를 결합합니다.
type DotJoin<A, B> =
A extends string
? B extends string
? `${A}.${B}`
: never
: never;
이 타입은 “부모 키 + 자식 키”를 문자열 규칙으로 안전하게 연결합니다.
핵심 설계 4: 모든 것을 조합해 키를 자동 생성한다
이제 모든 도구를 하나로 묶습니다.
type DeepKeys<T> = {
[K in keyof T]:
IsObject<T[K]> extends true
? DotJoin<K, DeepKeys<T[K]>>
: K;
}[keyof T];
이 타입은 다음을 보장합니다.
- 설정 객체 구조와 문자열 키가 항상 일치한다
- 키 추가/삭제 시 타입이 자동으로 갱신된다
- 사람이 직접 문자열을 관리하지 않는다
코드 예제: 실무에서 바로 쓰는 설정 키 패턴
이제 실제 설정 객체에 적용해봅니다.
const config = {
user: {
enabled: true,
beta: false,
},
order: {
enabled: true,
},
};
type ConfigKey = DeepKeys<typeof config>;
ConfigKey는 자동으로 다음 유니언이 됩니다.
- user.enabled
- user.beta
- order.enabled
이 구조에서는 설정과 타입이 어긋날 여지가 없습니다.
운영/실무에서 자주 겪는 문제
- 중첩이 너무 깊어 타입 에러 메시지가 길어지는 경우
- 모든 객체를 재귀 대상으로 처리한 경우
- 설정보다 타입이 먼저 이해되어야 하는 구조
- 팀원이 패턴을 수정하지 못하는 상황
이 패턴은 강력하지만, “설정 키처럼 반드시 자동화해야 하는 영역”에만 쓰는 것이 중요합니다.
실무 권장 체크리스트
- 문자열 키가 객체 구조와 1:1로 대응되는가
- 수동 문자열 관리로 인한 버그가 실제로 있었는가
- 재귀 깊이가 합리적인 수준인가
- 타입 정의를 팀원이 이해할 수 있는가
- 이 패턴이 중복 정의를 실제로 제거하는가
Mapped Types와 Conditional Types의 목적은 타입을 복잡하게 만드는 것이 아닙니다.
중복을 제거하고, 규칙을 한 곳에 고정하며, 실수를 구조적으로 불가능하게 만드는 것. 이 조건이 만족될 때, 문자열 키 자동 생성 패턴은 실무에서 훌륭한 도구가 됩니다.
'개발 > Typescript' 카테고리의 다른 글
| [TYPESCRIPT] 리팩터링 예제로 보는 타입 개선 과정: 나쁜 TypeScript 타입을 좋은 타입으로 바꾸는 방법 (0) | 2026.01.31 |
|---|---|
| [TYPESCRIPT] 타입 자동화 적용 한계: 권한·피처 플래그·환경 변수에서 멈춰야 할 지점 (0) | 2026.01.30 |
| [TYPESCRIPT] Template Literal Types 활용 전략: 문자열을 타입으로 안전하게 조작하는 방법 (0) | 2026.01.28 |
| [TYPESCRIPT] typescript 판단 기준 요약: 주니어부터 시니어까지 흔들리지 않는 선택 가이드 (0) | 2026.01.27 |
| [TYPESCRIPT] 타입 단순화 전략: 과도한 타입 설계를 멈추는 판단 기준 (0) | 2026.01.26 |
