Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

13. DeepReadonly #19

Open
astak16 opened this issue May 8, 2022 · 0 comments
Open

13. DeepReadonly #19

astak16 opened this issue May 8, 2022 · 0 comments
Labels

Comments

@astak16
Copy link
Owner

astak16 commented May 8, 2022

题目

题目链接: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 () => voidnever
  • keyof {}never

同时 never extends objecttrue

这样就把函数和空对象排除掉了

方法四

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

@astak16 astak16 added the medium label May 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant