我正在研究type-challenges中的question.

这就是要求:实现一个通用的MyReadonly2<T、 K>它接受两个类型参数T和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. The solution works fine in v4.4+, not in v4.5+.

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

重现问题:

v4.7.2中的解决方案:here

要解决此问题,请执行以下操作:

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

它在V4.7.2中运行良好.here


我就是想不出解决方案1不起作用的原因.

推荐答案

最初的行为被认为是TypeScript中的一个bug,归档于microsoft/TypeScript#45122,修正于microsoft/TypeScript#45263,并在TypeScript 4.5中发布.

TypeScript应该如何用同一个键的属性表示intersections种对象类型,其中有些是readonly properties种,但不是全部是readonly properties种?结果属性是否应为readonly?例如,{readonly a: string} & {a: string}应该等于{readonly a: string}还是{a: string}

从概念上讲,尽管名称不同,readonly表示"这是可读的",而非readonly表示"这是可读的and可写的".这就是为什么您可以将Array<string>视为ReadonlyArray<string>,但不能将Array<string>视为ReadonlyArray<string>.交集在概念上表示"and",因此{readonly a: string} & {a: string}应该是具有可读a属性的对象,以及具有可读写a属性的对象.这意味着最终a属性是可读写的,因此最终对象类型应该等于{a: string},不带readonly修饰符.根据该逻辑,如果最终对象属性在其出现的every个相交成员中为readonly,则该属性仅应为readonly.交点不能用于将readonly修改器设置为非readonly特性的add.

在TypeScript 4.5之前,TypeScript具有相反且不正确的行为,如果some个相交成员中的最终对象属性为readonly,则该属性为readonly.这是错误的,它被修复了.


这就是为什么您的代码在TypeScript 4.5中发生了更改.像T & Readonly<Pick<T, K>>这样的东西应该不能对K中的任何键进行readonly修改,因为这些键也存在于keyof T中.但是Omit<T, K> & Readonly<Pick<T, K>>可以添加readonly个修改器,因为K中的键都不在keyof Omit<T, K>中.由于不需要排除其他关键点,因此应该可以获得与Omit<T, K> & Readonly<T>相同的效果.

Typescript相关问答推荐

接口DOMRouter选项未输出

忽略和K的定义

webpack错误:模块找不到.当使用我的其他库时,

带占位符的模板文字类型何时扩展另一个?

使某些(嵌套)属性成为可选属性

如何表示多层深度的泛型类型数组?

在实现自定义主题后,Angular 不会更新视图

部分更新类型的类型相等

使用KeyOf和Never的循环引用

Vue3 Uncaught SyntaxError:每当我重新加载页面时,浏览器控制台中会出现无效或意外的令牌

在排版修饰器中推断方法响应类型

如何将别名添加到vitest配置文件?

自定义 Select 组件的类型问题:使用带逗号的泛型类型<;T与不带逗号的<;T&>;时出错

如何避免从引用<;字符串&>到引用<;字符串|未定义&>;的不安全赋值?

react 路由不响应参数

扩展对象的此内容(&Q;)

从以下内容之一提取属性类型

递归类型别名的Typescript 使用

可以将JS文件放在tsconfig';s includes/files属性?或者,我如何让tsc判断TS项目中的JS文件?

Typescript泛型-键入对象时保持推理