0007 · Readonly
0007 · Readonly
Problem
Implement the built-in Readonly<T> generic without using it.
Constructs a type with all properties of T set to readonly, meaning the properties of the constructed type cannot be reassigned.
interface Todo {
title: string
description: string
}
const todo: MyReadonly<Todo> = {
title: 'Hey',
description: 'foobar',
}
todo.title = 'Hello' // Error: cannot reassign a readonly property
todo.description = 'barFoo' // Error: cannot reassign a readonly propertySolution
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }Explanation
This solution is almost identical to Pick, but with the readonly modifier applied to every property.
Step by step:
keyof T— produces a union of all keys ofT[K in keyof T]— iterates over every keyKinTreadonly— marks each property as read-onlyT[K]— preserves the original value type of each property
The result is a new object type where all properties are read-only. Attempting to assign a value to any property will cause a TypeScript compile error.
Why readonly matters:
TypeScript's readonly modifier is a compile-time check only — the JavaScript runtime doesn't enforce it. But it's extremely useful for expressing intent (e.g., immutable state, frozen config objects) and catching accidental mutations early.
Key concepts:
Tips
A normal array (T[]) is a subtype of a readonly array (readonly T[]), because a mutable array can do everything a readonly array can (plus mutation). This is the Liskov Substitution Principle applied to TypeScript's type system.
中文解析
核心思路:
实现 MyReadonly<T> 的关键是使用映射类型(Mapped Types),对 T 的每个属性加上 readonly 修饰符。
// 解法
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }
// ^^^^^^^^ 映射类型修饰符,让每个属性变为只读逐步分析:
keyof T— 获取类型T所有键的联合类型[K in keyof T]— 遍历T的每一个键Kreadonly— 给每个属性加上只读修饰T[K]— 保留原属性的值类型不变
注意: readonly 只是 TypeScript 编译时检查,运行时的 JavaScript 并不会阻止赋值。若需要运行时不可变,应使用 Object.freeze()。
考察知识点:
- 映射类型(Mapped Types)
keyof操作符readonly修饰符
