yunliuyan / type-challenges

typescript-challenges
0 stars 2 forks source link

00007-medium-readonly-2 #7

Open yunliuyan opened 11 months ago

yunliuyan commented 11 months ago

Readonly 2 中等 #readonly #object-keys

by Anthony Fu @antfu

接受挑战    English 日本語 한국어

由谷歌自动翻译,欢迎 PR 改进翻译质量。

实现一个通用MyReadonly2<T, K>,它带有两种类型的参数TK

K指定应设置为Readonly的T的属性集。如果未提供K,则应使所有属性都变为只读,就像普通的Readonly<T>一样。

例如

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

测试案例:

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>>,
]

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
}

返回首页 分享你的解答 查看解答

相关挑战

7・实现 Readonly 9・深度 Readonly
yunliuyan commented 11 months ago

思路

遍历T的属性,若T的属性在K里面,则设为readonly,否则不设为readonly。 判断T的属性是否在K里面的方法: key in keyof T as key extends K ? 【在K里面执行的条件】: 【不在K里面执行的条件】

代码实现

type MyReadonly2<T, K> = {
  readyonly [rKey in keyof T as rKey extends K ? rKey : never]: T[rKey];
} & {
   [nKey in keyof T as nKey extends K ? never: nKey]: T[nKey];
}
liangchengv commented 11 months ago
type MyReadonly2<T, K extends keyof T> = {
  readonly [P in keyof Pick<T, K>]: T[P];
} & {
  [P in Exclude<keyof T, K>]: T[P];
};

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
wudu8 commented 11 months ago
/**
 * 实现一个readonly类型,只针对第一层属性只读,并且使用第二个泛型来设置那些属性只读
 */
type ILovePartialReadOnly<T, K extends keyof T> = {
    readonly [I in keyof Pick<T, K>]: T[I];
} & {
  [I in keyof Omit<T, K>]: T[I];
};

interface Todo1 {
    name: string;
    description: string;
    meta: {
        description: string;
    };
}

const partialTest: ILovePartialReadOnly<Todo1, 'name' | 'description'> = {
    name: "字节猿",
    description: "字节猿喜欢readonly",
    meta: {
        description: "ILoveReadOnly类型并不支持深层只读",
    },
};

partialTest.name = "abc"; // Error: Property 'title' does not exist on type 'ILoveReadOnly<Todo1>'.ts(2339
partialTest.description = "abc"; // Error: Property 'title' does not exist on type 'ILoveReadOnly<Todo1>'.ts(2339
partialTest.meta = {
  description: "我不是只读属性"
}; // Ok
Janice-Fan commented 11 months ago

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

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

Naparte commented 11 months ago

type MyReadonly2<T, K extends keyof T> = Pick<Readonly<T>, K> & Omit<T, K>;

interface Todo7 {
    title: string
    description: string
    ion: string
    completed: boolean
}

const todo7: MyReadonly2<Todo7, 'title' | 'description'> = {
    title: 'ssssss',
    description: 'ssssss',
    ion: 'ssssss',
    completed: true
}

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