Readonly
Readonly<Type>
构造一个类型使Type
的所有属性都设置为readonly
,这意味着构造类型的属性都是只读的,不能被修改,这对使用Object.freeze()
方法的对象非常有用。
基础
ts
// Make all properties in T readonly
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
例子
ts
// 创建 Fruit 接口
interface Fruit {
apple: string;
banana: number;
}
// 构造一个只读的 Fruit 接口
type ReadonlyFruit = Readonly<Fruit>;
/**
* ReadonlyFruit 的类型为:
* interface {
* readonly apple: string;
* readonly banana: number;
* }
*/
// 创建 fruit 实现 ReadonlyFruit 接口
const fruit: ReadonlyFruit = {
apple: 'apple',
banana: 1,
orange: {
color: 'orange',
weight: 3
}
}
// 修改 fruit.apple 会报错,因为 fruit中的apple 是只读的
fruit.apple = 'peach';
// 修改 fruit.orange.color 不会报错,因为 Readonly 不会深度冻结对象
fruit.orange.color = 'red';
注意
Readonly
- 构造函数不会影响原始类型,它只会影响构造类型的属性。
- 只能作用于浅度的属性,无法影响嵌套的对象。
进阶
处理深层嵌套的对象
ts
// 创建一个 DeepReadonly 类型
type DeepReadonly<T> = {
// 遍历 T 的所有属性
// 如果属性是一个对象,则递归调用 DeepReadonly,否则返回该属性本身
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
}
例子
ts
// 创建 Fruit 接口
interface Fruit {
apple: string;
banana: number;
orange: {
color: string;
weight: number;
}
}
// 创建一个 DeepReadonly 类型
type DeepReadonly<T> = {
// 遍历 T 的所有属性
// 如果属性是一个对象,则递归调用 DeepReadonly,否则返回该属性本身
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
}
// 实现 Fruit 接口
const fruit: DeepReadonly<Fruit> = {
apple: 'apple',
banana: 1,
orange: {
color: 'orange',
weight: 2
}
}
// 修改 fruit.apple 和 fruit.orange.color 会报错,因为它们是只读的
fruit.apple = 'peach';
fruit.orange.color = 'red';