TypeScript如何定义允许无、仅一个但禁止同时存在两个指定属性的类型
问题原因
你原先的写法错误地将需要禁止的属性声明为必填的never类型:b: never的语义是「必须存在b属性,且值的类型为never」,而never不存在合法的取值,这会导致你的三个接口本身就没有符合要求的合法实例,自然也无法实现你要的校验逻辑。
另外当你用{}作为NeitherANorB的替代时,由于空接口允许传入任意额外属性,自然也无法拦截同时存在a和b的场景。
解决方案
要表示「某个属性不允许存在」,正确的写法是将其声明为可选的never类型:属性名?: never,语义为「该属性要么不存在,要么存在时取值为never(无合法值)」。
修改后的完整代码如下:
interface JustA { a: string; b?: never; } interface JustB { b: string; a?: never; } interface NeitherANorB { a?: never; b?: never; } type NotBothAAndB = JustA | JustB | NeitherANorB; function testMe(x: NotBothAAndB) { console.log(x); } testMe({}); // OK testMe({ a: "HI!" }); // OK testMe({ b: "SUP?" }); // OK testMe({ a: "HI!", b: "SUP?" }); // 报错:不能将类型“{ a: string; b: string; }”分配给类型“NotBothAAndB”
通用扩展
如果需要更通用的互斥属性校验,可以封装通用工具类型:
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }; type XOR<T, U> = T | U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U; type OneOrNone<T, U> = XOR<T, U> | (Without<{}, T | U>; // 使用示例 type NotBothAAndB = OneOrNone<{a:string}, {b:string}>
内容的提问来源于stack exchange,提问作者Chris Pfohl
相关产品推荐
相关产品推荐

