「TS类型体操00007」实现 Readonly

334 阅读1分钟

题目

实现一个类型工具 MyReadonly<T>,接收一个类型参数T,返回一个和T完全一样的类型,只不过所有的属性都被 readonly 修饰。

例如:

interface Todo {
  title: string
  description: string
}

// 现在 todo 的 title 和 description 属性都是 readonly 的了。
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 property

原题链接

实现 Readonly

思路

类比 JavaScript

类比 JavaScript,就是实现一个函数:

这个函数接收一个老对象,创建一个新对象,把老对象的所有属性名都加上 readonly 前缀, 再拷贝给新对象,返回新对象。

function MyReadonly(obj) {
    const readonlyObj = {};
    
    for (const key in obj) {
        readonlyObj["readonly_" + key] = obj[key];
    }
    
    return readonlyObj;
}

提取逻辑点

1. 返回一个对象
2. 遍历一个对象的所有属性
3. 把对象的所有属性都加上 readonly 前缀
4. 提取对象特定属性的值

再把逻辑点翻译成 typescript 即可。

翻译成 TypeScript

typescript 实现上述逻辑点如下。

返回一个对象

// 返回一个 {} 即可
type MyReadonly<T> = {};

遍历一个对象的所有属性

通过 [P in K] 来遍历,这里的 K 得是一个 联合类型,如 'a'|'b'|'c',而 T 是一个 interface/对象type,所以需要通过 keyof 获取 T 的属性联合类型

[P in keyof T]

把对象的所有属性都加上 readonly 前缀

通过 readonly 关键字即可。

readonly [P in keyof T]

提取对象特定属性的值

通过 [] 提取,本例中以 T[P] 获取。

readonly [P in keyof T]: T[P]

实现

综上所述,最终的类型工具 MyReadonly 实现为:

type MyReadonly<T> = {
  readonly [P in keyof T]: T[P];
}