[Typescript] 17. Medium - Readonly 2

Implement a generic MyReadonly2<T, K> which takes two type argument T and K.

K specify the set of properties of T that should set to Readonly. When K is not provided, it should make all properties readonly just like the normal Readonly<T>.

For example

interface Todo {
  title: string
  description: string
  completed: boolean
}

const todo: MyReadonly2<Todo, 'title' | 'description'> = {
  title: "Hey",
  description: "foobar",
  completed: false,
}

todo.title = "Hello" // Error: cannot reassign a readonly property
todo.description = "barFoo" // Error: cannot reassign a readonly property
todo.completed = true // OK

 

/* _____________ Your Code Here _____________ */
// 1. Make all the props as readonly
// 2. & the prop not in K without readonly
// 3. K: set default value as keyof T, and should extends keyof T
type MyReadonly2<T, K extends keyof T = keyof T> = {
  readonly [P in keyof T]: T[P]
} & {
  [P in keyof T as P extends K ? never: P]: T[P]
}

type x = keyof Todo2
/* _____________ Test Cases _____________ */
import type { Alike, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Alike<MyReadonly2<Todo1>, Readonly<Todo1>>>,
  Expect<Alike<MyReadonly2<Todo1, 'title' | 'description'>, Expected>>,
  Expect<Alike<MyReadonly2<Todo2, 'title' | 'description'>, Expected>>,
]

// @ts-expect-error
type error = MyReadonly2<Todo1, 'title' | 'invalid'>

interface Todo1 {
  title: string
  description?: string
  completed: boolean
}

interface Todo2 {
  readonly title: string
  description?: string
  completed: boolean
}

interface Expected {
  readonly title: string
  readonly description?: string
  completed: boolean
}

 

Step by step:

1. Make all prop as readonly

type MyReadonly2<T, K extends keyof T = keyof T> = {
  readonly [P in keyof T]: T[P]
} 

type x = MyReadonly2<Todo1, 'title' | 'description'>

/*
type x = {
    readonly title: string;
    readonly description?: string | undefined;
    readonly completed: boolean;
}
*/

2. For prop not in K, make as not readonly

type MyReadonly2<T, K extends keyof T = keyof T> = {
  [P in keyof T as P extends K ? never: P]: T[P]
}

type x = MyReadonly2<Todo1, 'title' | 'description'>
/*
type x = {
    completed: boolean;
}
*/

3. Do intersection:

type MyReadonly2<T, K extends keyof T = keyof T> = {
  readonly [P in keyof T]: T[P]
} & {
  [P in keyof T as P extends K ? never: P]: T[P]
}

 4. K extends keyof T = keyof T set default value of K as keyof T if not defined and K should extends keyof T

posted @   Zhentiw  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2020-09-08 [CSS 3] content-visibility: auto Improve rendering performance
2020-09-08 [Machine Learning] Neural Networks: Representation Quiz
2018-09-08 [GraphQL] Query Local and Remote Data in Apollo Link State
2018-09-08 [Spring Boot ] Creating the Spring Boot Project : Demo: Creating a REST Controller
2018-09-08 [Web Analytics] Into to Web Analytics
2016-09-08 [AngularJS] Test an Angular Component with $componentController
2016-09-08 [AngularJS] Isolate State Mutations in Angular Components
点击右上角即可分享
微信分享提示