背景:(可跳过)
我正在摆弄一些
update(person: Person)
语句,通过允许它应该更新的属性子集来使其更可用。我想有两个选择:
Partial<Person>
或 Omit<Person, 'id'>
作为第二个参数。id
属性位于提供的对象中。所以
Omit
对我来说似乎是一个不错的候选者,但要省略的键可以是任何字符串值。
问题:
为什么 TypeScript 不强制提供给
Omit
的键值?我正在监督的还有什么好的用途吗?
看下面的代码
export interface Person {
id: string;
age: number;
name: string;
}
type UpdatePerson = Omit<Person, 'whatEver'>; // Why does 'whatEver' not cause compile issues?
type UpdatePerson2 = Pick<Person, 'id'> & Partial<Person>; // Great, a valid key is enforced here
type UpdatePerson3 = Pick<Person, 'thisDoesNotCompile'> & Partial<Person>; // This line fails compilation as that property isn't part of the interface
现在我选择
update(person: UpdatePerson)
和 type UpdatePerson = Pick<Person, 'id'> & Partial<Person>;
。这使得所有属性都是可选的,而 id 是强制的。
简而言之,选择此行为是为了使 内置
Omit
可以与现有的 DefinelyTyped 库最兼容。这些库已经在 Omit 是否应该严格的问题上存在分歧,选择更宽松的 Omit 可以防止这些现有库被破坏,但代价是编译器安全性和尚未编写的代码的自动完成功能稍差。
背景信息:这是在 microsoft/TypeScript#30825 中请求的,来自 DanielRosenwasser 的 此响应:
根据 DefinelyTyped 中的声明,受约束的
类型似乎会让至少一半的用户感到不满意。我们决定采用更宽松的内置功能,您可以在其中建立自己的约束。Omit
这些来自语言合著者Ryan Cavanaugh:
我必须澄清这个误解。 DT 上的 Omit 有 12 种不同的定义,其中两种最流行的定义在是否限制 [原文如此] 键上有所不同:[snip]
你可以挑选数字并尝试宣布民主多数或其他什么,但现实是,只有一个定义不会打破很大一部分人。
这是一个很受欢迎的请求,有重复项在 SO 和 在 GitHub,相应的简洁严格等价物很容易编写/导出,并且在其他库中也可用,例如
type-zoo
。
TypeScript 中内置的 Omit 实用程序是这样实现的:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
请注意,
K
受到 keyof any 的约束,它允许任何基于字符串的键,即使是 T
上不存在的键。这种设计允许灵活性,但牺牲了K
中按键的严格性。
为了制作一个更安全的 Omit 版本,确保仅可以省略
T
上存在的键,您可以通过对 K
进行更严格的约束来重新定义它:
type StrictOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
在此自定义 StrictOmit 中,
K
专门限制为 keyof T
,这意味着只有 T
上实际存在的属性才能指定为省略。如果您尝试省略 T
上不存在的键,TypeScript 将引发错误。
要结束,只需将自定义类型放入
global.d.ts
即可开始。