00009-medium-deep-readonly

Back

type Base = {
  id: number
  title: string
  address: {
    street: string
    city: string
  }
}
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
}

type DeepReadonlyBase = DeepReadonly<Base>

const todo: DeepReadonlyBase = {
  id: 1,
  title: 'Hello',
  address: {
    street: '123',
    city: 'world'
  }
}

Solution by semet #34642

Use recursive types. We should check T's recursive ending condition.


type DeepReadonly<T> = T extends symbol | Function ? T: {
  readonly [K in keyof T]: DeepReadonly<T[K]>;
}

Solution by dev-jaemin #34631

type DeepReadonly<T> = {
  readonly [P in keyof T]: 
    keyof T[P] extends never 
    ? T[P] 
    : DeepReadonly<T[P]>
}

Solution by binhdv155127 #34612

type DeepReadonly<T> = T extends object
  ? (
    T extends [ infer A, ...infer B ]
      ? readonly [ DeepReadonly<A>, ...DeepReadonly<B> ]
      : (
        T extends Function
          ? T
          : {
            readonly [P in keyof T]: DeepReadonly<T[P]>
          }
      )
  )
  : T

Solution by DevShinnThant #34561

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

Solution by emen #34492

最初的答案:

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends Object ? DeepReadonly<T[K]> : T[K];
}

运行之后发现第一个案例无法通过,究其原因,对于案例中的函数,也会被默认为一个对象,由此遇到函数就会进行无限的递归调用。

//解法一:将函数作为基本类型一起归类为不需要递归调用
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends string | number | null | undefined | boolean | ((...args: any[]) => any) ? T[K] : DeepReadonly<T[K]>;
}

//解法二:由于函数不能再拆分成更加基本的类型,可以采用never类型进行判断
type DeepReadonly<T>={
    readonly [K in keyof T]:T[K] extends never?T[K]:DeepReadonly<T[K]>
}

Solution by wxh-cyber #34476

type DeepReadonly<T> = T extends never ? T : {
  readonly [P in keyof T]: DeepReadonly<T[P]>
}

Solution by ktim816 #34432

type DeepReadonly<T> = {
  readonly [K in keyof T]: keyof T[K] extends never ? T[K] : DeepReadonly<T[K]>
}

Solution by rookie-luochao #34369

type DeepReadonly<T> = T extends any ? 
  keyof T extends never ? T : {
    readonly [P in keyof T]: keyof T[P] extends never ? T[P]: DeepReadonly<T[P]> 
  }
: never;

Solution by leaderiop #34234

type DeepReadonly<T extends {}> = {
  readonly [k in keyof T]: T[k] extends Function ? T[k] // 函数不需要递归
                          : T[k] extends {} ? DeepReadonly<T[k]> : T[k] // 如果是对象继续递归
}

Solution by quitone #34203

문제

객체의 프로퍼티와 모든 하위 객체를 재귀적으로 읽기 전용으로 설정하는 제네릭 DeepReadonly<T>를 구현하세요.

이 챌린지에서는 타입 파라미터 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 DeepReadonly<T> = {
	readonly [key in keyof T]: T[key] extends object
		? DeepReadonly<T[key]>
		: T[key];
};
type Y1 = {
    readonly a: DeepReadonly<() => 22>;
    readonly b: string;
    readonly c: DeepReadonly<{
        d: boolean;
        e: {
            g: {
                h: {
                    i: true;
                    j: "string";

다음과 작성했지만 예외 케이스를 통과하지 못했습니다. 제귀의 형태가 다소 이상하게 진행됨을 확인할 수 있었습니다. 저는 그 이유가 정확히 object를 찾아낼 방법이 필요하다고 생각했습니다. (원시타입이 아닌지)

keyof T[K] extends never

keyof는 객체 타입의 모든 키를 유니언 타입으로 반환합니다. 예를 들어, 객체 타입이 { a: string, b: number }라면, keyof { a: string, b: number }는 'a' | 'b'가 됩니다.

never는 TypeScript에서 어떤 값도 가질 수 없는 타입을 의미합니다. 예를 들어, 함수가 항상 예외를 던지거나 끝나지 않는 경우 그 반환 타입은 never가 됩니다. 또한, 빈 객체의 키 타입을 keyof로 추출하려고 하면 never가 됩니다

type DeepReadonly<T> = {
	readonly [K in keyof T]: keyof T[K] extends never ? T[K] : DeepReadonly<T[K]>;
};
type Y1 = {
    readonly a: () => 22;
    readonly b: string;
    readonly c: DeepReadonly<{
        d: boolean;
        e: {
            g: {
                h: {
                    i: true;
                    j: "string";

Solution

/* _____________ 여기에 코드 입력 _____________ */

type DeepReadonly<T> = {
	readonly [key in keyof T]: keyof T[key] extends never
		? T[key]
		: DeepReadonly<T[key]>;
};

/* _____________ 테스트 케이스 _____________ */
import type { Equal, Expect } from "@type-challenges/utils";

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 };

Solution by adultlee #34130

// 函数要单独考虑
type DeepReadonly<T extends object> = T extends any ? {
  readonly [P in keyof T]: T[P] extends object ? (T[P] extends Function ? T[P] : DeepReadonly<T[P]>) : T[P]
} : never

Solution by ouzexi #33986

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>

Solution by notsecret32 #33888

type DeepReadonly<T> = keyof T extends never ? T : {
  readonly [K in keyof T]: DeepReadonly<T[K]>
}

Solution by Danny101201 #33808

type DeepReadonly<T> = {
  readonly [P in keyof T]: keyof T[P] extends never
    ? T[P]
    : DeepReadonly<T[P]>
}

Solution by laplace1009 #33714

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object
    ? T[K] extends Function
      ? T[K]
      : DeepReadonly<T[K]>
    : T[K];
};

Solution by Alex-Nicalace #33668

// 你的答案
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends Function ? T[P] :DeepReadonly<T[P]>
}

Solution by heyuelan #33660

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

Solution by OgabekYuldoshev #33584

type DeepReadonly<T> = {
  readonly [Prop in keyof T]: T[Prop] extends (...args: any) => any
    ? T[Prop]
    : T[Prop] extends object
    ? DeepReadonly<T[Prop]>
    : T[Prop];
};```

Solution by Kolufs #33537

type DeepReadonly<T> = {
  readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>;
};

Solution by partiality #33344

// 你的答案
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

Solution by 2531800823 #33239

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

Solution by Tubring25 #33224

type Builtin = Function | Date | Error | RegExp;

type DeepReadonly<T> = T extends Builtin ? T : {
  readonly [K in keyof T]: DeepReadonly<T[K]>
}

Solution by daishi-motoyama #33186

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

Solution by KenjiGinjo #33090

// your answers

type DeepReadonly<T> = T extends unknown ? {
  readonly [P in keyof T]: T[P] extends Function
    ? T[P]
    : T[P] extends object
      ? DeepReadonly<T[P]>
      : T[P]
} : never


Solution by KeithChou #33079

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

Solution by Taneros #33014

// 你的答案
type DeepReadonly<T> = {
  readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>
}

Solution by Mohaiyo #32957

/**
 * T extends Record<string, unknown> | Array<unknown>:
 * 这个条件表达式表示我们希望泛型 T 能够接受任意类型,
 * 但是我们只关注对象类型(使用 Record<string, unknown> 表示)和数组类型(使用 Array<unknown> 表示)。

? { readonly [P in keyof T]: DeepReadonly<T[P]> }:
这是条件类型的第一个分支。当 T 是对象类型时,我们使用映射类型来递归地处理对象的每个属性。
对于对象的每个属性 P,我们将其设为只读,并递归地调用 DeepReadonly 泛型来处理属性值 T[P],以确保其嵌套对象也被设为只读。

: T:这是条件类型的第二个分支。当 T 不是对象类型时(例如字符串、数字等基本类型),我们不做任何处理,直接返回 T。
 */
type DeepReadonly<T> = T extends Record<string, unknown> | Array<unknown>
  ? { readonly [P in keyof T]: DeepReadonly<T[P]> }
  : T;

Solution by CAN1177 #32855

// 解答をここに記入
type DeepReadonly<T> = {
  readonly [Key in keyof T]: T[Key] extends Function
    ? T[Key]
    : T[Key] extends object
      ? DeepReadonly<T[Key]>
      : T[Key];
}

Solution by Yasunori-aloha #32811

type DeepReadonly<T> =
  T extends T ? keyof T extends never
    ? T
    : { readonly [k in keyof T]: DeepReadonly<T[k]> }
  : never

Solution by sunhuoxyr #32810