You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改TypeScript代码以禁止同时使用a和b属性?

How to enforce mutual exclusivity between a and b properties in TypeScript?

Great question! The issue with your current code is that TypeScript’s structural typing system lets extra properties slide when checking against a union. Your D = (A | B) & C type is equivalent to (A & C) | (B & C)—so an object with both a and b still matches the A & C branch (since it has the required a and c properties), which is why d2 doesn’t throw an error.

To fix this and make TypeScript block objects that have both a and b, you need to enforce mutual exclusivity between the two properties. Here are two straightforward approaches:

Approach 1: Add exclusive never properties directly to A and B

You can modify your base types to explicitly declare that the other property must be absent (or set to never):

type A = { a: number; b?: never; }
type B = { b: number; a?: never; }
type C = { c: number; }
type D = (A | B) & C;

const d0: D = { a: 123, c: 123 } // ✅ Valid (only `a` and `c`)
const d1: D = { b: 123, c: 123 } // ✅ Valid (only `b` and `c`)
const d2: D = { a: 123, b: 123, c: 123 } // ❌ Error: Type '{ a: number; b: number; c: number; }' is not assignable to type 'D'

How this works:

  • By adding b?: never to A, we’re saying: "if this type has an a property, it can’t have a b property (or if it does, b must be never, which is unassignable to any real value)."
  • Similarly, a?: never in B ensures that objects with b can’t have a valid a property.
  • Now, an object with both a and b won’t match either A or B, so it can’t be assigned to D.

Approach 2: Use a reusable exclusive type utility

If you don’t want to modify your original A and B types, you can create a generic utility type that enforces mutual exclusivity between any two types:

type A = { a: number; }
type B = { b: number; }
type C = { c: number; }

// Utility type to make two types mutually exclusive
type Exclusive<T, U> = 
  (T & Partial<Record<keyof U, never>>) | 
  (U & Partial<Record<keyof T, never>>);

type D = Exclusive<A, B> & C;

const d0: D = { a: 123, c: 123 } // ✅ Valid
const d1: D = { b: 123, c: 123 } // ✅ Valid
const d2: D = { a: 123, b: 123, c: 123 } // ❌ Error: Type '{ a: number; b: number; c: number; }' is not assignable to type 'D'

How this works:

  • The Exclusive<T, U> type creates two branches:
    1. T & Partial<Record<keyof U, never>>: An object that matches T, and any properties from U must be never (optional, thanks to Partial).
    2. U & Partial<Record<keyof T, never>>: The reverse—an object that matches U, with any T properties set to never.
  • When combined with C, this ensures that D only accepts objects that have either a or b (but not both), plus the required c property.

Both approaches will effectively block objects that include both a and b, giving you the type safety you’re looking for.

内容的提问来源于stack exchange,提问作者Just Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 22:52:46