mcpField
E
exclusive-or-properties

exclusive-or-properties

github.com/marius-townhouseDevelopment646 installsUpdated 39w ago
Repository

About exclusive-or-properties

exclusive-or-properties is a skill for TypeScript developers who need mutually exclusive configuration, component props, or API parameters. It uses optional never properties and unions to enforce exactly-one constraints at compile time.

Key features

  1. 01Enforce exclusivity with optional never properties
  2. 02Define valid variants with unions
  3. 03Cover component props and API parameters
  4. 04Provide reusable XOR helper types
  5. 05Check combinations at compile time

Use cases

  1. 01Require exactly one configuration source
  2. 02Restrict a component to one action mode
  3. 03Model mutually exclusive API parameter forms

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill exclusive-or-properties

After installing, type/exclusive-or-propertiesin Claude Code to confirm it loaded.

Details

From the project README

Use Optional Never Properties to Model Exclusive Or

Overview

Sometimes you need a type where exactly one of several properties must be present, but not more than one. This "exclusive or" (XOR) pattern is common in component props, API parameters, and configuration objects. Using optional properties with never types enforces this constraint at compile time.

This technique provides better type safety than unions of objects and clearer intent than runtime checks.

When to Use This Skill

  • Exactly one of several properties must be present
  • Modeling mutually exclusive configuration options
  • Component props with alternative configurations
  • API parameters that have exclusive variants
  • Preventing invalid combinations of properties

The Iron Rule

Use optional never properties to enforce "exactly one of" constraints. Each variant makes its property required and others never.

Detection

Watch for these invalid combinations:

// RED FLAGS - Invalid combinations allowed
interface Config {
  url?: string;
  filePath?: string;
  content?: string;
}
// Can pass none, one, or all - too permissive!

// Runtime validation needed:
if ((config.url ? 1 : 0) + (config.filePath ? 1 : 0) + (config.content ? 1 : 0) !== 1) {
  throw new Error('Exactly one source required');
}

The Problem

interface LoadConfig {
  url?: string;      // Load from URL
  filePath?: string; // Load from file
  content?: string;  // Load from string
}

// All these are allowed, but shouldn't be:
const bad1: LoadConfig = {};  // No source specified
const bad2: LoadConfig = { url: '...', filePath: '...' };  // Two sources
const bad3: LoadConfig = { url: '...', filePath: '...', content: '...' };  // All three

// Runtime check required
function load(config: LoadConfig) {
  const sources = [config.url, config.filePath, config.content].filter(Boolean);
  if (sources.length !== 1) {
    throw new Error('Exactly one source required');
  }
  // ...
}

The Solution: Optional Never Properties

type LoadConfig =
  | { url: string; filePath?: never; content?: never }
  | { url?: never; filePath: string; content?: never }
  | { url?: never; filePath?: never; content: string };

// Valid - exactly one source:
const good1: LoadConfig = { url: 'https://example.com' };
const good2: LoadConfig = { filePath: '/path/to/file' };
const good3: LoadConfig = { content: 'raw content' };

// Invalid - caught at compile time:
const bad1: LoadConfig = {};  // Error: missing required property
const bad2: LoadConfig = { url: '...', filePath: '...' };  // Error: filePath must be undefined
const bad3: LoadConfig = { url: '...', content: '...' };   // Error: content must be undefined

Component Props Example

type ButtonProps = {
  label: string;
  onClick: () => void;
} & (
  | { href: string; to?: never; onPress?: never }      // External link
  | { href?: never; to: string; onPress?: never }     // Router link
  | { href?: never; to?: never; onPress: () => void } // Custom action
);

// Usage
<Button label="External" href="https://example.com" />
<Button label="Internal" to="/dashboard" />
<Button label="Action" onPress={handlePress} />

// Error: can't combine variants
<Button label="Bad" href="..." to="..." />  // Error!

API Parameters Example

type SearchParams = {
  limit?: number;
  offset?: number;
} & (
  | { query: string; filters?: never }
  | { query?: never; filters: Filter[] }
);

// Valid
search({ query: 'typescript' });
search({ filters: [{ field: 'status', value: 'active' }] });
search({ query: 'typescript', limit: 10 });

// Invalid
search({});  // Error: need query or filters
search({ query: '...', filters: [...] });  // Error: can't have both

Generic XOR Helper

type XOR<A, B> =
  | (A & { [K in keyof B]?: never })
  | (B & { [K in keyof A]?: never });

// Usage
type Config = XOR<
  { url: string },
  XOR<
    { filePath: string },
    { content: string }
  >
>;

// Or for exactly one of many:
type ExactlyOne<T> = {
  [K in keyof T]: { [P in K]: T[K] } & {
    [P in Exclude<keyof T, K>]?: never;
  };
}[keyof T];

type LoadConfig2 = ExactlyOne<{
  url: string;
  filePath: string;
  content: string;
}>;

Pressure Resistance Protocol

When enforcing exclusive properties:

  1. Identify exclusivity: Which properties are mutually exclusive?
  2. Create variants: Each variant has one required, others never
  3. Union the variants: Combine with | operator
  4. Test combinations: Ensure invalid combos fail
  5. Document the pattern: Explain why certain combos are invalid

Red Flags

Anti-PatternProblemSolution
All optional propertiesAllows none or manyOptional never pattern
Runtime validation onlyErrors at runtime, not compile timeType-level enforcement
Comments saying "use only one"Not enforcedMake it a type error

Common Rationalizations

"I'll validate at runtime"

Reality: Runtime validation catches bugs later. Type-level enforcement catches them immediately.

"This is too verbose"

Reality: Use helper types like XOR or ExactlyOne to reduce repetition.

"Users might want multiple options"

Reality: If that's valid, don't use XOR. If it's not, enforce it at the type level.

Quick Reference

PatternSyntaxMeaning
XOR (2 props){ a: T, b?: never } | { a?: never, b: T }Exactly one
XOR (3+ props)Union of variantsExactly one
Helper typeXOR<A, B>Reusable pattern

The Bottom Line

Use optional never properties to enforce "exactly one of" constraints at compile time. This eliminates an entire class of runtime errors and makes invalid states unrepresentable.

Reference

  • Effective TypeScript, 2nd Edition by Dan Vanderkam
  • Item 63: Use Optional Never Properties to Model Exclusive Or

Comments

Markdown supported