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:
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.
If
a
is optional and means thatb
orc
shouldn't be there,{}
(a completely empty object) is a validFoo
.
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
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