날짜 표기를 통일하는 데 매핑 객체가 필요 없다 — dayjs는 포맷 문자열이 곧 키이자 값이라, 허용 표기를 as const 배열 하나로 두면 그게 닫힌 집합이다. 닫힘은 union 타입이, 통로는 함수 하나가 맡는다. (i18n은 키≠값이라 객체가 필수였지만, 여기선 잉여.)
import dayjs from 'dayjs'
// 허용 표기의 단일 출처 — union 타입과 ESLint drift 가드가 여기서 파생
export const DATE_FORMATS = [
'YYYY-MM-DD',
'YYYY-MM-DDTHH:mm:ss',
'HH:mm',
'YYYY년 M월',
'YY년 M월 D일',
'YYYY.MM.DD',
'YY.MM.DD',
'YYYY.MM.DD(ddd)',
'YYYY.MM.DD HH:mm',
] as const
export type DateFormat = (typeof DATE_FORMATS)[number]
export const formatDate = (
date: dayjs.ConfigType,
format: DateFormat,
): string => dayjs(date).format(format)
규율: 여러 곳에서 통일이 필요한 표기만 배열에 담는다. 일회성('M.D' 등)은 raw dayjs().format()으로 인라인 유지 — 안 그러면 배열이 잡동사니 enum이 된다. ESLint no-restricted-syntax로 카탈로그 표기를 raw로 다시 쓰면 경고(drift 가드).
ddd(요일)는 진입점에서 dayjs.locale('ko')를 호출해야 한국어로 나온다 — 안 하면 영어로 조용히 샌다. 타입은 이 런타임 전제를 못 잡는다.
곁가지 — 매핑 객체·빌드타임 hoist·tagged-template 캐시도 검토했으나 접음: 고유 패턴이 수십 개 규모라 dedup·컴파일 최적화가 풀 문제 자체가 없다. 닫힌 타입 + 함수 하나로 충분.