持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
题目
实现一个通用的DeepReadonly<T>,它将对象的每个参数及其子对象递归地设为只读。
可以假设在此挑战中仅处理对象。数组,函数,类等都无需考虑。
例如
type X = {
x: {
a: 1
b: 'hi'
}
y: 'hey'
}
type Expected = {
readonly x: {
readonly a: 1
readonly b: 'hi'
}
readonly y: 'hey'
}
type Todo = DeepReadonly<X> // should be same as `Expected`
DeepReadonly用来将一个嵌套对象类型中所有字段全部添加readonly关键词,例如:
// 类型:
type X = {
b: string
c: {
d: boolean
e: undefined,
f: null
}
}
// 结果:
type Y = {
readonly b: string
readonly c: {
readonly d: boolean
readonly e: undefined,
readonly f: null
}
}
解答
题目中已经将解答思路说得很清楚了。一个是要将属性设置为readonly,另一个关键点就是属性值可能是对象,因此需要递归地进行设置。第一个点应该很简单了,我们在<ReadOnly 2>的实现中已经实现了按需的readonly,因此关键在于如何递归地设置readonly.
首先回顾下Readonly的写法:
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
-
这里对于每个属性的值来说没有进行判断,直接返回
T[P],而T[P]可能是一个对象类型,因此需要用到extends条件类型进行判断:T[P] extends { [key: string]: any } ? A : B -
如果
T[P]是对象类型,那么继续调用<DeepReadonly>进行处理,如果不是直接返回T[P].
汇总一下,得到最终结果:
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends { [key: string]: any } ? DeepReadonly<T[P]> : T[P]
}