Typescript Omit< ...>:未省略的类型可以赋值给省略的类型,如何设置类型以避免这种情况发生?

tzdcorbm  于 2023-04-07  发布在  TypeScript
关注(0)|答案(1)|浏览(142)

Typescript很好地为我服务,它使JavaScript免于成为有史以来编写的最糟糕的编程语言之一,但它并非没有它的奇怪设计和“陷阱”。
问题:

  • 如何让Omit<...>以可靠的方式运行,而不会在下面的代码中创建场景?换句话说,如何设置它们的类型,以便在下面的代码中抛出错误?
type NonOmittedObj = {
  keepThisProp: string
  omitThisProp: string
}
type OmittedObj = Omit<NonOmittedObj, 'omitThisProp'>

const nonOmittedObj: NonOmittedObj = {
  keepThisProp: 'foo',
  omitThisProp: 'bar',
}
// It is very counterintuitive that this is allowed and does not throw an error
// If it isn't blatantly obvious why this is counterintuitive, the word "omit" is defined as "to leave out or exclude." With that said, the omitted props are being included, not excluded, so the behavior is contradicting the meaning of the word "omit."
const omittedObj: OmittedObj = nonOmittedObj

下面是一个类比,说明为什么这种行为是反直觉设计的:
假设我有一组名为“省略了小丑的牌”的牌。然后,当我发现这副牌中有小丑时,我会生气地说“为什么这副牌中有小丑??”当nonOmittedObj被分配给omittedObj时,这感觉就像把小丑从另一副牌里拿出来,放进标着“这副牌不能包含任何小丑”的牌里。这感觉就像不应该被允许。

erhoui1w

erhoui1w1#

要创建一个严格的Omit,您需要将其删除键定义为never
https://tsplay.dev/NVY4vw

type NonOmittedObj = {
  keepThisProp: string
  omitThisProp: string
}
const nonOmittedObj: NonOmittedObj = {
  keepThisProp: 'foo',
  omitThisProp: 'bar',
}

type SurelyOmit<T, K extends keyof T> = {
    [P in keyof T]: P extends K ? never : T[K]
}
type OmittedObj = Omit<NonOmittedObj, 'omitThisProp'>
//   ^?
// type OmittedObj = { keepThisProp: string; }
type SmittedObj = SurelyOmit<NonOmittedObj, 'omitThisProp'>
//   ^?
// type SmittedObj = { keepThisProp: string; omitThisProp: never; }


const omittedObj: OmittedObj = nonOmittedObj
// ok

const smittedObj: SmittedObj = nonOmittedObj
//    ^!
// Type 'NonOmittedObj' is not assignable to type 'SurelyOmit<NonOmittedObj, "omitThisProp">'.
//   Types of property 'omitThisProp' are incompatible.
//     Type 'string' is not assignable to type 'never'.(2322)

相关问题