"매 TypeScript 의 const assertion — literal type 으로 widening 차단". 매 TS 3.4 (2019) 도입. 매 array → readonly tuple, object → readonly with literal types. 매 enum 대안, discriminated union 의 핵심, type-safe routing/config 의 enabler.
매 핵심
매 widening behavior
매 default: const x = "hello" → 매 type string (literal type widened).
매 wait, const 변수는 literal 유지: const x = "hello" → "hello". 매 그러나 object property 는 widened: { name: "alice" } → { name: string }.
as const 의 효과: 매 모든 nested literal 유지 + readonly + tuple inference.
매 변환 규칙
String/number/boolean literal: 매 widened type 매 → literal type.
Object { a: 1 }: 매 { a: number } → { readonly a: 1 }.
Nested: 매 deep recursive 적용.
매 응용
Discriminated unions: 매 kind: "circle" as const 로 narrow.
Action creators (Redux): 매 type 이 literal string 으로 inferred.
Route configs: 매 path 가 literal string 으로 inferred → type-safe Link to=.
Tuple returns: 매 return [value, setter] as const — React custom hook pattern.
enum 대안: 매 const Status = { Idle: "idle", Loading: "loading" } as const.
💻 패턴
Tuple return — custom hook
functionuseToggle(initial=false){const[on,setOn]=useState(initial);consttoggle=useCallback(()=>setOn(o=>!o),[]);return[on,toggle]asconst;// 매 type: readonly [boolean, () => void]
// 매 without `as const`: (boolean | (() => void))[] — useless union
}const[isOpen,toggle]=useToggle();// 매 properly typed
constStatus={Idle:"idle",Loading:"loading",Success:"success",Error:"error",}asconst;typeStatus=typeofStatus[keyoftypeofStatus];// 매 "idle" | "loading" | "success" | "error"
functionsetStatus(s: Status){/* ... */}setStatus(Status.Loading);// ok
setStatus("loading");// ok — literal type
setStatus("invalid");// 매 type error
Type-safe config / route table
constroutes={home:"/",user:"/user/:id",settings:"/settings",}asconst;typeRouteKey=keyoftypeofroutes;typeRoutePath=typeofroutes[RouteKey];// 매 "/" | "/user/:id" | "/settings"
functionLink<KextendsRouteKey>({to}:{to: K}){return<ahref={routes[to]}>...</a>;}
Array of literals → union
constSIZES=["sm","md","lg","xl"]asconst;typeSize=typeofSIZES[number];// 매 "sm" | "md" | "lg" | "xl"
functionButton({size}:{size: Size}){/* */}// 매 runtime + type 동시 derive — 매 single source of truth.
SIZES.forEach(s=>console.log(s));// runtime iterable
언제: custom hook tuple return, enum 대체, action creator, route/config table 의 type-safety, discriminated union narrowing 의.
언제 X: 매 mutable 한 runtime data (readonly 가 방해), 매 simple primitive 의 (const x = 1 매 already literal).
❌ 안티패턴
as cast 와 혼동: 매 as const 매 special — as Foo (type assertion) 와 다름.
Mutable assumption: 매 as const array 매 readonly — .push() X. [...arr] spread 후 mutate.
Object 의 partial as const: 매 nested object 의 일부만 const 의도 — 매 not possible. 매 전체 deep 매 readonly.
enum + as const 동시: 매 redundant. enum 자체로 literal type.
JSON.stringify 의 사용: 매 JSON 화하면 readonly 손실 — runtime 에서 의미 없음.