实现一个泛型 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`
答案
// 判断一个类型是否有键 type HasKey<T> = T extends object ? (keyof T extends never ? false : true) : false type DeepReadonly<T> = { readonly [K in keyof T]: HasKey<T[K]> extends true ? DeepReadonly<T[K]> : T[K] }
要考虑覆盖更多的类型,可以参考 Vue 源码:
type Primitive = string | number | boolean | bigint | symbol | undefined | null type Builtin = Primitive | Function | Date | Error | RegExp type DeepReadonly<T> = T extends Builtin ? T : T extends Map<infer K, infer V> ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>> : T extends ReadonlyMap<infer K, infer V> ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>> : T extends WeakMap<infer K, infer V> ? WeakMap<DeepReadonly<K>, DeepReadonly<V>> : T extends Set<infer U> ? ReadonlySet<DeepReadonly<U>> : T extends ReadonlySet<infer U> ? ReadonlySet<DeepReadonly<U>> : T extends WeakSet<infer U> ? WeakSet<DeepReadonly<U>> : T extends Promise<infer U> ? Promise<DeepReadonly<U>> : T extends {} ? { readonly [K in keyof T]: DeepReadonly<T[K]> } : Readonly<T>