1 | import type {Except} from './except';
|
2 | import type {HomomorphicPick, IfArrayReadonly} from './internal';
|
3 | import type {KeysOfUnion} from './keys-of-union';
|
4 | import type {OptionalKeysOf} from './optional-keys-of';
|
5 | import type {Simplify} from './simplify';
|
6 | import type {UnknownArray} from './unknown-array';
|
7 |
|
8 | /**
|
9 | Create a type that makes the given keys required. The remaining keys are kept as is. The sister of the `SetOptional` type.
|
10 |
|
11 | Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are required.
|
12 |
|
13 | @example
|
14 | ```
|
15 | import type {SetRequired} from 'type-fest';
|
16 |
|
17 | type Foo = {
|
18 | a?: number;
|
19 | b: string;
|
20 | c?: boolean;
|
21 | }
|
22 |
|
23 | type SomeRequired = SetRequired<Foo, 'b' | 'c'>;
|
24 | // type SomeRequired = {
|
25 | // a?: number;
|
26 | // b: string; // Was already required and still is.
|
27 | // c: boolean; // Is now required.
|
28 | // }
|
29 |
|
30 | // Set specific indices in an array to be required.
|
31 | type ArrayExample = SetRequired<[number?, number?, number?], 0 | 1>;
|
32 | //=> [number, number, number?]
|
33 | ```
|
34 |
|
35 | @category Object
|
36 | */
|
37 | export type SetRequired<BaseType, Keys extends keyof BaseType> =
|
38 | BaseType extends UnknownArray
|
39 | ? SetArrayRequired<BaseType, Keys> extends infer ResultantArray
|
40 | ? IfArrayReadonly<BaseType, Readonly<ResultantArray>, ResultantArray>
|
41 | : never
|
42 | : Simplify<
|
43 | // Pick just the keys that are optional from the base type.
|
44 | Except<BaseType, Keys> &
|
45 | // Pick the keys that should be required from the base type and make them required.
|
46 | Required<HomomorphicPick<BaseType, Keys & KeysOfUnion<BaseType>>>
|
47 | >;
|
48 |
|
49 | /**
|
50 | Remove the optional modifier from the specified keys in an array.
|
51 | */
|
52 | type SetArrayRequired<
|
53 | TArray extends UnknownArray,
|
54 | Keys,
|
55 | Counter extends any[] = [],
|
56 | Accumulator extends UnknownArray = [],
|
57 | > = TArray extends unknown // For distributing `TArray` when it's a union
|
58 | ? keyof TArray & `${number}` extends never
|
59 | // Exit if `TArray` is empty (e.g., []), or
|
60 | // `TArray` contains no non-rest elements preceding the rest element (e.g., `[...string[]]` or `[...string[], string]`).
|
61 | ? [...Accumulator, ...TArray]
|
62 | : TArray extends readonly [(infer First)?, ...infer Rest]
|
63 | ? '0' extends OptionalKeysOf<TArray> // If the first element of `TArray` is optional
|
64 | ? `${Counter['length']}` extends `${Keys & (string | number)}` // If the current index needs to be required
|
65 | ? SetArrayRequired<Rest, Keys, [...Counter, any], [...Accumulator, First]>
|
66 | // If the current element is optional, but it doesn't need to be required,
|
67 | // then we can exit early, since no further elements can now be made required.
|
68 | : [...Accumulator, ...TArray]
|
69 | : SetArrayRequired<Rest, Keys, [...Counter, any], [...Accumulator, TArray[0]]>
|
70 | : never // Should never happen, since `[(infer F)?, ...infer R]` is a top-type for arrays.
|
71 | : never; // Should never happen
|