C.W.K.
Stream
Lesson 03 of 05 · published

`readonly` 배열과 Tuple

~8 min · arrays-tuples, readonly, immutability

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"Readonly 배열은 배열의 type system 이 '읽을 수 있어, 쓸 수 없어' 말하는 거. Runtime 은 여전히 허용 — 근데 compiler 가 소리쳐."

readonly 배열 모양

타입 레벨에서 배열을 read-only 로 표시하는 동등한 2 문법: readonly T[] (modifier) 와 ReadonlyArray<T> (utility-type alias). 같은 타입 만들어 — mutation method (push, pop, shift, unshift, splice, sort, reverse, fill) 가 타입에서 제거된 배열. 읽기 (length, index 접근, map, filter, slice, 등) 는 여전히 허용.

Runtime 에 배열은 일반 배열. `readonly` modifier 는 type layer 에만 존재; JavaScript 엔진이 강제 안 함. 다른 TypeScript 와 일관: compile-time contract, runtime erasure.

readonly tuple

Tuple 도 같은 modifier 받아: readonly [number, string]. 전체 tuple — 길이와 위치별 writability 둘 다 — 가 freeze. 보너스: tuple literal 의 `as const` 가 자동으로 readonly tuple 만들어, 그 idiom 이 흔한 이유 중 하나.

왜 함수 parameter 를 readonly 로 annotate

함수가 배열 argument 를 mutate 할 의도 없으면, parameter 를 `readonly T[]` 로 타입. 두 이득: compiler 가 함수 안에서 우발적 mutate 안 하는지 강제 AND callsite 가 너가 그들 데이터 안 바꿀 거 알아. 조합이 비용 없이 한 단어 안전 개선.

function sumAll(items: readonly number[]): number {
  // items.push(0)   // ❌ 안에서 잡힘
  return items.reduce((acc, n) => acc + n, 0);
}
알아둘 비대칭: 일반 배열이 `readonly` 배열에 assignable (mutation method 제거가 widening 이니까). `readonly` 배열이 일반 배열에 assignable 아님 (mutation method 추가가 가진 것보다 더 약속하는 거니까). 데이터가 readonly 영역에 한 번 넘어가면, 복사 없이 돌아갈 수 없어.

피파의 고백

cwkPippa frontend 가 함수 parameter 에 `readonly T[]` default 로 가려고 시도. 한 mindset 에서 다른 거로 전환 비용은 한 keyword; 이득은 누적되는 수십 개의 작은 "우발적 mutate 마" 보장. 예외 — 함수가 mutate 하길 원할 때 — 는 주석으로 표시할 가치 있을 만큼 드물어.

Code

readonly modifier — 허용되는 것, 아닌 것·typescript
// 배열의 readonly modifier.
const frozen: readonly number[] = [1, 2, 3];
frozen[0] = 99;       // ❌ Index signature in type 'readonly number[]' only permits reading
frozen.push(4);       // ❌ Property 'push' does not exist on type 'readonly number[]'

// 읽기 연산은 여전히 허용.
const doubled = frozen.map((n) => n * 2);       // ✅
const length = frozen.length;                    // ✅

// readonly tuple.
type Pair = readonly [number, number];
const p: Pair = [1, 2];
p[0] = 99;            // ❌ readonly

// readonly 가 one-way 관계.
const mutable: number[] = [1, 2, 3];
const alsoFrozen: readonly number[] = mutable;   // ✅ readonly 로 widening
// const backToMutable: number[] = alsoFrozen;    // ❌ 복사 없이 readonly 떨굴 수 없음
const copy: number[] = [...alsoFrozen];          // ✅ 명시적 복사
readonly parameter — 작은 단어, 큰 invariant·typescript
// 함수 parameter — 채택해야 할 default.

function summarize(items: readonly string[]): string {
  // items.sort()   // ❌ mutate 함 — 잡힘
  return items.join(', ');
}

// Sort 필요하면 먼저 복사.
function summarizeSorted(items: readonly string[]): string {
  return [...items].sort().join(', ');
}

// Caller 한테 신호: '너의 데이터 안 만질 거.'
const raw = ['c', 'a', 'b'];
summarize(raw);          // ✅ — raw 그대로
summarizeSorted(raw);    // ✅ — raw 그대로

External links

Exercise

User[] 받고 email list 반환하는 함수 가져와. Parameter 에 readonly 추가. 함수 안 뭐 깨져? 그러면 조정 (sort 면 아마 [...users]) 하고 readonly 버전이 이제 caller 에게 더 안전한 거 봐.
Hint
대부분 read-only 체인 (map, filter, reduce) 살아남아. Sort, splice, 직접 index assign 은 실패. Fix 는 거의 항상 '먼저 복사'.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.