-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
Description
题目
题目链接:DeepReadonly
实现类型 DeepReadonly
,将对象的每个子对象也变成只读。
import type { Equal, Expect } from "@type-challenges/utils";
type cases = [Expect<Equal<DeepReadonly<X>, Expected>>];
type X = {
a: () => 22;
b: string;
aa: {};
c: {
d: boolean;
e: {
g: {
h: { i: true; j: "string" };
k: "hello";
};
l: ["hi", { m: ["hey"] }];
};
};
};
type Expected = {
readonly a: () => 22;
readonly b: string;
readonly aa: {};
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 DeepReadonly<T> = T extends object & { call?: never }
? { readonly [key in keyof T]: DeepReadonly<T[key]> }
: T;
知识点
{call?: never}
是用来排除函数的
方法二
type DeepReadonly<T> = {
readonly [key in keyof T]: T[key] extends Function
? T[key]
: T[key] extends object
? DeepReadonly<T[key]>
: T[key];
};
知识点
通过 T[key] extends Function
判断是不是函数,不是函数的话在判断是不是 object
方法三
type DeepReadonly<T> = {
readonly [key in keyof T]: keyof T[key] extends never
? T[key]
: DeepReadonly<T[key]>;
};
// 等价于
type DeepReadonly<T> = {
readonly [key in keyof T]: keyof T[key] extends object
? T[key]
: DeepReadonly<T[key]>;
};
// 等价于
type DeepReadonly<T> = keyof T extends never
? T
: { readonly [key in keyof T]: DeepReadonly<T[key]> };
// 等价于
type DeepReadonly<T> = keyof T extends object
? T
: { readonly [key in keyof T]: DeepReadonly<T[key]> };
知识点
keyof T[key] extends never
,如果 T[key]
为函数或者空对象, keyof T[key]
结果为 never
keyof () => void
⇒never
keyof {}
⇒never
同时 never extends object
⇒ true
这样就把函数和空对象排除掉了
方法四
type DeepReadonly<T> = T extends Record<string, unknown> | Array<unknown>
? { readonly [key in keyof T]: DeepReadonly<T[key]> }
: T;
知识点
const a: Record<string, unknown> = () => 1; // 报错
const c: Record<string, any> = () => 1; // 不报错
所以 Record<string, unknown>
不能用 any
代替 unknown