Files
2nd/10_Wiki/Topics/Frontend/as const.md
T
koriweb 95cd8bb891 feat(wiki): 코드 그라운딩 23문서 + MOC 학습지도 39개
- 코드 그라운딩: 기술 주제 문서의 '적용 사례'에 실제 레포 구현 위치
  (file:line)+커밋 자동 주입 (예: 문서 청킹 전략→connectai/src/retrieval/chunker.ts).
  멱등 마커(CODE-GROUNDING)로 재실행 시 갱신.
- MOC: 39개 클러스터 폴더에 _MOC.md 학습지도 생성(진입점+통찰 주석).
도구: Datacollect/scripts/{code_grounding,moc_generator}.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 18:56:11 +09:00

7.3 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-as-const as const 10_Wiki/Topics verified self
as const
const assertion
TypeScript const assertion
none A 0.9 applied
typescript
types
const-assertion
literal-types
2026-05-10 pending
language framework
typescript typescript-5

as const

매 한 줄

"매 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.
  • Array [1, 2, 3]: 매 number[]readonly [1, 2, 3] (tuple).
  • Object { a: 1 }: 매 { a: number }{ readonly a: 1 }.
  • Nested: 매 deep recursive 적용.

매 응용

  1. Discriminated unions: 매 kind: "circle" as const 로 narrow.
  2. Action creators (Redux): 매 type 이 literal string 으로 inferred.
  3. Route configs: 매 path 가 literal string 으로 inferred → type-safe Link to=.
  4. Tuple returns: 매 return [value, setter] as const — React custom hook pattern.
  5. enum 대안: 매 const Status = { Idle: "idle", Loading: "loading" } as const.

💻 패턴

Tuple return — custom hook

function useToggle(initial = false) {
  const [on, setOn] = useState(initial);
  const toggle = useCallback(() => setOn(o => !o), []);
  return [on, toggle] as const;
  // 매 type: readonly [boolean, () => void]
  // 매 without `as const`: (boolean | (() => void))[] — useless union
}

const [isOpen, toggle] = useToggle(); // 매 properly typed

Discriminated union via const

const success = (data: string) => ({ kind: "success", data } as const);
const error = (msg: string) => ({ kind: "error", msg } as const);

type Result = ReturnType<typeof success> | ReturnType<typeof error>;
// { readonly kind: "success"; readonly data: string }
// | { readonly kind: "error"; readonly msg: string }

function handle(r: Result) {
  if (r.kind === "success") {
    r.data; // string
  } else {
    r.msg; // string
  }
}

Enum 대안 (lighter, tree-shakeable)

const Status = {
  Idle: "idle",
  Loading: "loading",
  Success: "success",
  Error: "error",
} as const;

type Status = typeof Status[keyof typeof Status];
// 매 "idle" | "loading" | "success" | "error"

function setStatus(s: Status) { /* ... */ }
setStatus(Status.Loading); // ok
setStatus("loading"); // ok — literal type
setStatus("invalid"); // 매 type error

Type-safe config / route table

const routes = {
  home: "/",
  user: "/user/:id",
  settings: "/settings",
} as const;

type RouteKey = keyof typeof routes;
type RoutePath = typeof routes[RouteKey];
// 매 "/" | "/user/:id" | "/settings"

function Link<K extends RouteKey>({ to }: { to: K }) {
  return <a href={routes[to]}>...</a>;
}

Array of literals → union

const SIZES = ["sm", "md", "lg", "xl"] as const;
type Size = typeof SIZES[number];
// 매 "sm" | "md" | "lg" | "xl"

function Button({ size }: { size: Size }) { /* */ }

// 매 runtime + type 동시 derive — 매 single source of truth.
SIZES.forEach(s => console.log(s)); // runtime iterable

Action creators (Redux Toolkit 이전 패턴)

const incrementAction = (n: number) => ({
  type: "counter/increment",
  payload: n,
} as const);

type IncrementAction = ReturnType<typeof incrementAction>;
// { readonly type: "counter/increment"; readonly payload: number }

Deep readonly via as const

const config = {
  api: {
    baseUrl: "https://api.example.com",
    timeout: 5000,
  },
  features: ["auth", "billing"],
} as const;

config.api.baseUrl = "..."; // 매 error: readonly
config.features.push("new"); // 매 error: readonly
config.api.baseUrl; // type: "https://api.example.com" (literal)

satisfies + as const (TS 4.9+)

const palette = {
  red: "#ff0000",
  blue: "#0000ff",
  green: "#00ff00",
} as const satisfies Record<string, `#${string}`>;

palette.red; // type: "#ff0000" — literal preserved
// 매 satisfies validates shape, as const preserves literals.

매 결정 기준

상황 Approach
Custom hook tuple return as const 필수.
Enum 대체 as const object + typeof[keyof].
Config / route table as const + satisfies (TS 4.9+).
Discriminated union kind: "x" as const literal narrow.
Mutable runtime data as const 사용 X — readonly 가 방해.

기본값: 매 const literal 유지 필요 시 as const. 매 type validation 까지 매 as const satisfies.

🔗 Graph

🤖 LLM 활용

언제: 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 에서 의미 없음.

🧪 검증 / 중복

  • Verified (TypeScript Handbook, TS 3.4 release notes).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — const assertion patterns, enum 대안, discriminated union, satisfies combo 추가

🛠️ 적용 사례 (Applied in summary)

🔎 코드베이스 근거 (자동 추출 — E:\Wiki 레포)

실제 구현/사용 위치:

  • photoai/src/shared/constants.ts:4 — export const SUPPORTED_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.webp'] as const
  • photoai/src/preload/inference.ts:13 — ] as const
  • photoai/src/main/menu.ts:107 — type: 'radio' as const,
  • connectai/src/features/hire/hireStore.ts:26 — export const KNOWN_STAGES = ['inbox', 'screened', 'interview', 'final', 'offer', 'accepted', 'hired', 'rejected', 'decli
  • connectai/src/features/datacollect/handlers.ts:117 — for (const part of [1, 2, 3] as const) {

자동 생성: code_grounding.mjs · 재실행 시 갱신됨