Files
2nd/10_Wiki/Topics/Architecture/readonly.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

5.0 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-readonly TypeScript readonly 10_Wiki/Topics verified self
readonly
Readonly<T>
ReadonlyArray
as const
none A 0.9 applied
typescript
immutability
types
2026-05-10 pending
language framework
typescript typescript

TypeScript readonly

매 한 줄

"매 compile-time 매 immutability marker — runtime enforcement 의 X". 매 TS 의 의 의 mutation prevention 의 의 매 type-system level — readonly keyword, Readonly<T>, ReadonlyArray<T>, as const 매 4 가지 form. 매 runtime freeze 가 의 매 Object.freeze 의 의.

매 핵심

매 4 가지 form

  • Property modifier: interface User { readonly id: string } — assign once.
  • Mapped type: Readonly<T> — all props readonly (shallow).
  • Array variants: readonly T[] 또는 ReadonlyArray<T> — no .push, .pop, etc.
  • as const: literal narrowing + deep readonly tuple/object literal.

매 핵심 행동

  • 매 compile-time only — JS runtime 의 의 effect 의 X.
  • Variance: T[] is assignable to readonly T[] (covariant), but not vice-versa.
  • Shallow: Readonly<{ a: { b: 1 } }> 매 a is readonly, a.b 의 X.

매 응용

  1. Public API: function param 매 readonly T[] — caller 의 mutation 의 의 의 의.
  2. Redux / Zustand state — 매 immutability invariant.
  3. Config object — as const 매 literal type.
  4. Tuple destructuring — const point = [1, 2] as const.
  5. Discriminated union literals — type Status = "ok" | "fail" via as const.

💻 패턴

Property readonly

interface User { readonly id: string; name: string }
const u: User = { id: "1", name: "A" };
u.name = "B";   // OK
u.id = "2";     // Error: cannot assign to 'id' because it is a read-only

Readonly<T> mapped

type Frozen<T> = Readonly<T>;
const cfg: Frozen<{ host: string; port: number }> = { host: "x", port: 80 };
cfg.host = "y"; // Error

Deep readonly

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

const data: DeepReadonly<{ user: { id: number } }> = { user: { id: 1 } };
data.user.id = 2; // Error

readonly T[] in API

function sum(xs: readonly number[]): number {
  // xs.push(1); // Error
  return xs.reduce((a, b) => a + b, 0);
}
sum([1, 2, 3]);                  // OK
sum(new Array(3).fill(0));       // OK

as const (literal narrowing)

const ROLES = ["admin", "user", "guest"] as const;
type Role = typeof ROLES[number]; // "admin" | "user" | "guest"

const config = { host: "localhost", port: 80 } as const;
// type: { readonly host: "localhost"; readonly port: 80 }

Tuple as const

function point() { return [1, 2] as const; } // [1, 2] 매 readonly tuple
const [x, y] = point();

Combine with branded type

type ImmutableUser = Readonly<{ id: string & { __brand: "UserId" }; email: string }>;

Runtime + type (Object.freeze + as const)

function deepFreeze<T>(o: T): Readonly<T> {
  Object.freeze(o);
  for (const k of Object.keys(o as object) as (keyof T)[]) {
    const v = o[k];
    if (v && typeof v === "object" && !Object.isFrozen(v)) deepFreeze(v);
  }
  return o;
}
const FROZEN = deepFreeze({ a: { b: 1 } });

매 결정 기준

상황 Approach
Public function param readonly T[]
Config / constants as const
Class field 매 once-set readonly modifier
Runtime guarantee 필요 Object.freeze (or Immer)
Deep immutability type Custom DeepReadonly<T>

기본값: 매 input param 매 readonly, 매 constants 매 as const. 매 runtime needed 시 Immer.

🔗 Graph

🤖 LLM 활용

언제: API design (input param immutability), config typing, state management types. 언제 X: Runtime tamper-proof 필요 (use freeze), JS-only project.

안티패턴

  • readonly 가 deep 일 거라 가정: 매 shallow only — DeepReadonly 사용.
  • as cast 으로 우회: 매 escape hatch — type system 의 매 무용.
  • Readonly<T> + ReadonlyArray<T> 혼동: object vs array, Mapped vs interface.
  • Mutating returned readonly array (via as): 매 compile pass 의 매 runtime corruption.
  • Class field readonly 의 매 setter 통한 mutation: 매 readonly 가 매 init time 만.
  • Public API 매 T[] (mutable): 매 caller 의 의 mutation 가능 — 항상 readonly T[] 권장.

🧪 검증 / 중복

  • Verified (TypeScript handbook, TC39 records & tuples proposal, MS TypeScript blog).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — readonly forms, as const, DeepReadonly pattern