Skip to content

对象属性只读(递归)

411字约1分钟

2022-12-01

题目

Github: Deep Readonly

实现一个通用的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`

解题思路

通过 readonly 修饰属性为 只读属性。

通过 T extends Record<any, any> 判断是否为对象,如果是,使用 readonly 修饰属性为 只读属性, 并对 T[P] 递归调用 DeepReadonly

由于 Function 继承自 Object,所以需要单独处理 Function 类型。

答案

type DeepReadonly<T> = T extends Function 
  ? T 
  : T extends Record<any, any>
    ?  { readonly [P in keyof T]: DeepReadonly<T[P]> }
    : T

验证

type 
cases
= [
Expect
<
Equal
<
DeepReadonly
<
X1
>,
Expected1
>>,
Expect
<
Equal
<
DeepReadonly
<
X2
>,
Expected2
>>,
] type
X1
= {
a
: () => 22
b
: string
c
: {
d
: boolean
e
: {
g
: {
h
: {
i
: true
j
: 'string'
}
k
: 'hello'
}
l
: [
'hi', {
m
: ['hey']
}, ] } } } type
X2
= {
a
: string } | {
b
: number }
type
Expected1
= {
readonly
a
: () => 22
readonly
b
: string
readonly
c
: {
readonly
d
: boolean
readonly
e
: {
readonly
g
: {
readonly
h
: {
readonly
i
: true
readonly
j
: 'string'
} readonly
k
: 'hello'
} readonly
l
: readonly [
'hi', { readonly
m
: readonly ['hey']
}, ] } } } type
Expected2
= { readonly
a
: string } | { readonly
b
: number }

参考