1 | /**
|
2 | Create a type that requires exactly one of the given keys and disallows more. The remaining keys are kept as is.
|
3 |
|
4 | Use-cases:
|
5 | - Creating interfaces for components that only need one of the keys to display properly.
|
6 | - Declaring generic keys in a single place for a single use-case that gets narrowed down via `RequireExactlyOne`.
|
7 |
|
8 | The caveat with `RequireExactlyOne` is that TypeScript doesn't always know at compile time every key that will exist at runtime. Therefore `RequireExactlyOne` can't do anything to prevent extra keys it doesn't know about.
|
9 |
|
10 | @example
|
11 | ```
|
12 | import type {RequireExactlyOne} from 'type-fest';
|
13 |
|
14 | type Responder = {
|
15 | text: () => string;
|
16 | json: () => string;
|
17 | secure: boolean;
|
18 | };
|
19 |
|
20 | const responder: RequireExactlyOne<Responder, 'text' | 'json'> = {
|
21 | // Adding a `text` key here would cause a compile error.
|
22 |
|
23 | json: () => '{"message": "ok"}',
|
24 | secure: true
|
25 | };
|
26 | ```
|
27 |
|
28 | @category Object
|
29 | */
|
30 | export type RequireExactlyOne<ObjectType, KeysType extends keyof ObjectType = keyof ObjectType> =
|
31 | {[Key in KeysType]: (
|
32 | Required<Pick<ObjectType, Key>> &
|
33 | Partial<Record<Exclude<KeysType, Key>, never>>
|
34 | )}[KeysType] & Omit<ObjectType, KeysType>;
|