Skip to content

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'; 

Released under the MIT License.