假设我有一个界面
interface ICart {
property1?: string,
propert2?: string,
someOtherProperty: string
}
我如何强制只允许property1和property2中的一个被允许,但其中一个必须存在?
答案 0 :(得分:1)
如果要只允许列表中的一个属性,则需要union对象类型,其中每个对象类型都允许一个特定属性,而不允许所有其他属性。 TypeScript并不能完全禁止您使用特定属性,但是您可以做些接近的事情:将其设为值类型为never
的可选属性。实际上,这将允许类型为undefined
的属性,但是undefined
属性和缺少的属性之间并没有太大的区别(和差异isn't captured well in TypeScript anyway)。
因此,对于上面的示例,所需的类型如下:
type ICartManual = {
property1: string;
property2?: undefined;
someOtherProperty: string;
} | {
property1?: undefined;
property2: string;
someOtherProperty: string;
}
您可以验证它的行为是否符合您的期望:
const i1: ICartManual = {
property1: "prop1",
someOtherProperty: "other"
}
const i2: ICartManual = {
property2: "prop2",
someOtherProperty: "other"
}
const iBoth: ICartManual = { // error!
// ~~~~~ <-- property1 is incompatible with undefined
property1: "prop1",
property2: "prop2",
someOtherProperty: "other"
}
const iNeither: ICartManual = { // error!
// ~~~~~~~~ <-- property2 is missing
someOtherProperty: "other"
}
如果您的界面较大,并且希望采用两种对象类型T
和U
并新建一个对象,则该对象需要T
中的一个属性,而{{1 }},您可以这样定义它:
U
这使用一堆mapped和conditional类型来构建所需的联合。我可以解释它是如何工作的,但是要花很多时间。我以前也做过类似的事情。可以在here中找到类似类型的更详细说明。
无论如何,我们现在可以像这样定义type OneKeyFrom<T, M = {}, K extends keyof T = keyof T> = K extends any ?
(M & Pick<Required<T>, K> & Partial<Record<Exclude<keyof T, K>, never>>) extends infer O ?
{ [P in keyof O]: O[P] } : never : never;
:
ICart
并且您可以验证(例如,通过IntelliSense)它与手动编写的类型相同(除了属性写入的顺序,它不会改变类型):
type ICart = OneKeyFrom<{ property1: string, property2: string }, { someOtherProperty: string }>;
好的,希望能有所帮助;祝你好运!
答案 1 :(得分:0)
// utility type which blocks two properties of the object coexisting
type NeverTogether<A extends object, Key1 extends keyof A, Key2 extends keyof A extends Key1 ? never : keyof A> =
Omit<A, Key1 | Key2> & (({
[k in Key1]: A[Key1]
} & {[k in Key2]?: never}) | ({
[k in Key1]?: never
} & {[k in Key2]: A[Key2]}))
interface ICart {
property1: string,
property2: string,
someOtherProperty: string
}
type IC = NeverTogether<ICart, 'property1', 'property2'>;
// error never together
const a: IC = {
property1: '1',
property2: '2',
someOtherProperty: '2'
}
// error one needs to be there
const b: IC = {
someOtherProperty: '2'
}
// correct
const c: IC = {
property2: '2',
someOtherProperty: '2'
}
// correct
const d: IC = {
property1: '1',
someOtherProperty: '2'
}
NeverTogether
类型存在的问题是为了使更多密钥具有这样的规则而引起的。因此,对于两个从属字段效果很好,但不能使其工作更多。但这也许会对您有所帮助。对我来说,这是一个解决难题的好方法。