你自找的。
让我们进行一些类型操作来检测给定类型是否是联合。它的工作方式是使用分配性的条件类型的属性将联合扩展到成分,然后注意每个成分都比联合更窄。如果这不是真的,那是因为工会只有一个成员(所以它不是工会):
type IsAUnion<T, Y = true, N = false, U = T> = U extends any
? ([T] extends [U] ? N : Y)
: never;
然后用它来检测给定的string
type 是单个字符串文字(所以:不是string
, not never
,而不是联合):
type IsASingleStringLiteral<
T extends string,
Y = true,
N = false
> = string extends T ? N : [T] extends [never] ? N : IsAUnion<T, N, Y>;
现在我们可以开始讨论您的具体问题。定义BaseObject
作为的一部分ComboObject
您可以直接定义:
type BaseObject = { known: boolean, field: number };
并准备错误消息,让我们定义一个ProperComboObject
这样当你搞砸时,错误会给出一些关于你应该做什么的提示:
interface ProperComboObject extends BaseObject {
'!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!': string
}
主菜来了。VerifyComboObject<C>
需要一个类型C
如果符合您的要求,则原封不动地退回ComboObject
类型;否则它返回ProperComboObject
(它也不符合)错误。
type VerifyComboObject<
C,
X extends string = Extract<Exclude<keyof C, keyof BaseObject>, string>
> = C extends BaseObject & Record<X, string>
? IsASingleStringLiteral<X, C, ProperComboObject>
: ProperComboObject;
它的工作原理是解剖C
into BaseObject
和其余的钥匙X
. If C
不匹配BaseObject & Record<X, string>
,那么你就失败了,因为这意味着它要么不是BaseObject
,或者它是一个带有额外的非string
特性。然后,它确保有正好一个剩余密钥,通过检查X
with IsASingleStringLiteral<X>
.
现在我们创建一个辅助函数,它要求输入参数匹配VerifyComboObject<C>
,并返回输入不变。如果您只想要正确类型的对象,它可以让您及早发现错误。或者您可以使用签名来帮助您自己的函数需要正确的类型:
const asComboObject = <C>(x: C & VerifyComboObject<C>): C => x;
让我们测试一下:
const okayComboObject = asComboObject({
known: true,
field: 123,
unknownName: 'value'
}); // okay
const wrongExtraKey = asComboObject({
known: true,
field: 123,
unknownName: 3
}); // error, '!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!' is missing
const missingExtraKey = asComboObject({
known: true,
field: 123
}); // error, '!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!' is missing
const tooManyExtraKeys = asComboObject({
known: true,
field: 123,
unknownName: 'value',
anAdditionalName: 'value'
}); // error, '!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!' is missing
第一个根据需要进行编译。最后三个失败的原因与额外属性的数量和类型有关。错误消息有点神秘,但这是我能做的最好的事情。
您可以在中查看正在运行的代码操场.
再说一次,我不认为我建议在生产代码中这样做。我喜欢玩类型系统,但这个感觉特别复杂而脆弱,并且我不想对任何事情负责不可预见的后果.
希望对您有帮助。祝你好运!