背景
假设我有一个包含所有可选值的接口:
interface MyInterface
{
property1?: string
property2?: string
proeprty3?: string
}
当使用MyInterface
作为类型时,我可以使用以下实用程序类型指定至少需要它的一个属性:
type AtLeastOnePropRequired<T> = { [P in keyof T]-?: Record<P, T[P]> }[keyof T]
type CustomRequired<T> = T & AtLeastOnePropRequired<T>
使用示例:
// At least one of `property1`, `property2`, or `property3` is required.
CustomRequired<MyInterface>
这有点类似于Required
,只是实用程序类型会使所有属性都是强制的,而不仅仅是一个.
顺便说一句,这里有另一种实现AtLeastOnePropRequired
的方法:
type AtLeastOnePropRequired<T> = T & { [P in keyof T]: Required<Pick<T, P>> }[keyof T]
问题
假设我想扩展MyInterface
并添加一个新的属性,它也是可选的:
interface NewInterface extends MyInterface
{
property4?: boolean
}
这里的皱纹是,我不能再以同样的方式使用CustomRequired
.如果我使用CustomRequired<NewInterface>
,它的意思是:
property1
、property2
、property3
或property4
中的至少一个 是必需的.
我需要的是一个打字,意思是:
至少需要
property1
、property2
或property3
中的一个.property4
是可选的,但如果提供,则不满足前面的 要求.
请参见下面的"结论"部分,了解这可能是什么样子的用法示例.
我试着调整CustomRequired
度来处理这种情况.
示例
下面是一个不应满足类型要求的示例:
// Does not contain one of `property1`, `property2`, or `property3`.
{
property4: false
}
下面是一些示例,说明了什么应该满足类型要求:
// Does contain one of `property1`, `property2`, or `property3`.
{
property1: "hello world!",
property3: "goodbye world!"
}
// Does contain one of `property1`, `property2`, or `property3`.
{
property2: "hello again!",
property4: false
}
结论
如果不是扩展MyInterface
,而是执行以下操作,就可以实现这种行为:
interface NewInterface
{
myInterface: CustomRequired<MyInterface>
property4?: boolean
}
现在,至少有一个属性MyInterface
必须提供给NewInterface
的myInterface
属性,但它很笨重,如果可能的话,我宁愿使用extend
方法.
我想象它可能工作的方式是,除了将接口传递给实用程序类型CustomRequired
之外,我还传递了不满足"至少一个"要求的属性名的联合.类似于Omit
和Exclude
的工作方式.
例如:
interface MyInterface
{
property1?: string
property2?: string
proeprty3?: string
}
interface NewInterface extends MyInterface
{
property4?: boolean
}
// At least one property of `NewInterface` is required, and any property will satisfy it.
// This is the current implementation.
CustomRequired<NewInterface>
// At least one property of `NewInterface` is required, but `property4` won't satisfy it.
CustomRequired<NewInterface, 'property4'>
// At least one property of `NewInterface` is required, but neither `property1` nor `property4` will satisfy it.
CustomRequired<NewInterface, 'property1' | 'property4'>
如果实用程序类型能够处理上面没有传递键的联合的情况,以及传递联合的情况,那就太好了.如果这是不可能的,那么有一个单独的实用类型将是可以的,只有当需要传递一个union时才使用,在其他情况下,任何属性将满足要求,我将使用我现有的实用类型.
我对TypeScript泛型还不够精通,无法马上弄清楚如何做到这一点.我认为这将涉及到将第二个泛型传递给CustomRequired
和AtLeastOnePropRequired
,然后对引用keyof T
的部分进行调整,以确保它不是联合泛型的一部分.