Home > Software design >  If "a" prop is true, require also "b" and "c"
If "a" prop is true, require also "b" and "c"

Time:12-07

I have a type:

type Foo = {
  a: boolean;
  b: string;
  c: string;
}

How to adjust it so if a is true, b and c fields MUST be provided. But if a is false or undefined, b and c MUST NOT be provided?

CodePudding user response:

You can use a discriminated union, but beware that:

  1. In general, preventing an object from having properties through TypeScript's type system is problematic because objects can have excess properties. TypeScript prevents assigning an object literal defining excess properties because it's a common programming mistake, but doesn't disallow it in the general case.

  2. If a is optional and means that b or c shouldn't be there, {} (a completely empty object) is a valid Foo.

type Foo =
    | {
          a: true;
          b: string;
          c: string;
      }
    | {
          a?: false;
      };

// Valid
const a: Foo = { a: true, b: "bee", c: "see" };

// Valid
const b: Foo = { a: false };

// Valid
const c: Foo = {};

// Invalid, but only if you're directly assigning an object literal
const d: Foo = { a: false, b: "whatever" };

// This is allowed, because an object can have excess properties
const someObject = { a: false, b: "whatever" } as const;
const e: Foo = someObject; // <== No error

Playground link

CodePudding user response:

What you're looking for is called a discriminated union in typescript.

The type might look something like this:

type Foo = 
  | { a: true, b: string, c: string }
  | { a?: false | undefined | null }

This accounts for the following cases:

const foo: Foo = { a: false } // valid
const foo: Foo = { } // valid
const foo: Foo = { a: true, b: "foo", c: "foo" } // valid

const foo: Foo = { a: true } // invalid
const foo: Foo = { a: undefined, b: "foo" } // invalid
const foo: Foo = { a: false, b: "foo" } // invalid
const foo: Foo = { a: false, b: "foo", c: "foo" } // invalid
  • Related