TypeScript如何定义含任意属性且a/b/c需同时存在的对象类型?
Solution to Enforce "All or None" for Specific Object Properties
Got it, let's tackle this TypeScript type problem you're facing. The core issue with a basic union type is that it doesn't block partial inclusion of a, b, or c—we need to explicitly define two mutually exclusive cases and combine them properly:
- The object has none of
a,b, orc(but can have any other properties) - The object has all three of
a,b, andc(plus any other properties)
Step-by-Step Implementation
First, let's define the two distinct types, then combine them into a union:
// Type 1: Object has NO a/b/c properties (can have any other props) type NoABC = Record<string, unknown> & { a?: never; b?: never; c?: never; }; // Type 2: Object has ALL a/b/c properties (plus any other props) // Replace string with your actual desired type for a/b/c type HasABC = Record<string, unknown> & { a: string; b: string; c: string; }; // Final union type enforcing "all or none" for a/b/c type MyType = NoABC | HasABC;
How This Works
- The
NoABCtype usesneverfora,b,cto ensure those properties cannot exist (if you try to add any of them, TypeScript will throw an error becausenevercan't be assigned to any value). - The
HasABCtype explicitly requires all three properties, while allowing extra properties viaRecord<string, unknown>. - The union ensures an object must fit one of these two cases—no partial inclusion allowed.
Test Cases to Validate
Let's check if this behaves as expected:
// ✅ Valid: No a/b/c, with other props const valid1: MyType = { x: 42, name: "Alice" }; // ✅ Valid: Has all a/b/c, plus other props const valid2: MyType = { a: "foo", b: "bar", c: "baz", isActive: true }; // ❌ Invalid: Only has 'a' (violates both NoABC and HasABC) const invalid1: MyType = { a: "foo" }; // ❌ Invalid: Has 'a' and 'b' but no 'c' const invalid2: MyType = { a: "foo", b: "bar" };
Generic Version (For Reusability)
If you want to reuse this pattern for other sets of properties or different types, create a generic type:
type RequireAllOrNone<Props extends string, PropType> = // Case 1: None of the specified props exist (Record<string, unknown> & { [K in Props]?: never }) | // Case 2: All specified props exist with the given type (Record<string, unknown> & { [K in Props]: PropType }); // Usage example for a/b/c as numbers type MyNumberType = RequireAllOrNone<'a' | 'b' | 'c', number>;
This way you can easily adapt the logic to other property sets or data types without rewriting the whole structure.
内容的提问来源于stack exchange,提问作者Flauwekeul
相关产品推荐
相关产品推荐

