1 | /**
|
2 | Create a deep version of another object type where property values are recursively replaced into a given value type.
|
3 |
|
4 | Use-cases:
|
5 | - Form validation: Define how each field should be validated.
|
6 | - Form settings: Define configuration for input fields.
|
7 | - Parsing: Define types that specify special behavior for specific fields.
|
8 |
|
9 | @example
|
10 | ```
|
11 | import type {Schema} from 'type-fest';
|
12 |
|
13 | interface User {
|
14 | id: string;
|
15 | name: {
|
16 | firstname: string;
|
17 | lastname: string;
|
18 | };
|
19 | created: Date;
|
20 | active: boolean;
|
21 | passwordHash: string;
|
22 | attributes: ['Foo', 'Bar']
|
23 | }
|
24 |
|
25 | type UserMask = Schema<User, 'mask' | 'hide' | 'show'>;
|
26 |
|
27 | const userMaskSettings: UserMask = {
|
28 | id: 'show',
|
29 | name: {
|
30 | firstname: 'show',
|
31 | lastname: 'mask',
|
32 | },
|
33 | created: 'show',
|
34 | active: 'show',
|
35 | passwordHash: 'hide',
|
36 | attributes: ['mask', 'show']
|
37 | }
|
38 | ```
|
39 |
|
40 | @category Object
|
41 | */
|
42 | export type Schema<ObjectType, ValueType, Options extends SchemaOptions = {}> = ObjectType extends string
|
43 | ? ValueType
|
44 | : ObjectType extends Map<unknown, unknown>
|
45 | ? ValueType
|
46 | : ObjectType extends Set<unknown>
|
47 | ? ValueType
|
48 | : ObjectType extends ReadonlyMap<unknown, unknown>
|
49 | ? ValueType
|
50 | : ObjectType extends ReadonlySet<unknown>
|
51 | ? ValueType
|
52 | : ObjectType extends Array<infer U>
|
53 | ? Options['recurseIntoArrays'] extends false | undefined
|
54 | ? ValueType
|
55 | : Array<Schema<U, ValueType>>
|
56 | : ObjectType extends (...arguments_: unknown[]) => unknown
|
57 | ? ValueType
|
58 | : ObjectType extends Date
|
59 | ? ValueType
|
60 | : ObjectType extends Function
|
61 | ? ValueType
|
62 | : ObjectType extends RegExp
|
63 | ? ValueType
|
64 | : ObjectType extends object
|
65 | ? SchemaObject<ObjectType, ValueType, Options>
|
66 | : ValueType;
|
67 |
|
68 | /**
|
69 | Same as `Schema`, but accepts only `object`s as inputs. Internal helper for `Schema`.
|
70 | */
|
71 | type SchemaObject<
|
72 | ObjectType extends object,
|
73 | K,
|
74 | Options extends SchemaOptions,
|
75 | > = {
|
76 | [KeyType in keyof ObjectType]: ObjectType[KeyType] extends
|
77 | | readonly unknown[]
|
78 | | unknown[]
|
79 | ? Options['recurseIntoArrays'] extends false | undefined
|
80 | ? K
|
81 | : Schema<ObjectType[KeyType], K, Options>
|
82 | : Schema<ObjectType[KeyType], K, Options> | K;
|
83 | };
|
84 |
|
85 | /**
|
86 | @see Schema
|
87 | */
|
88 | export type SchemaOptions = {
|
89 | /**
|
90 | By default, this affects elements in array and tuple types. You can change this by passing `{recurseIntoArrays: false}` as the third type argument:
|
91 | - If `recurseIntoArrays` is set to `true` (default), array elements will be recursively processed as well.
|
92 | - If `recurseIntoArrays` is set to `false`, arrays will not be recursively processed, and the entire array will be replaced with the given value type.
|
93 |
|
94 | @example
|
95 | ```
|
96 | type UserMask = Schema<User, 'mask' | 'hide' | 'show', {recurseIntoArrays: false}>;
|
97 |
|
98 | const userMaskSettings: UserMask = {
|
99 | id: 'show',
|
100 | name: {
|
101 | firstname: 'show',
|
102 | lastname: 'mask',
|
103 | },
|
104 | created: 'show',
|
105 | active: 'show',
|
106 | passwordHash: 'hide',
|
107 | attributes: 'hide'
|
108 | }
|
109 | ```
|
110 |
|
111 | @default true
|
112 | */
|
113 | readonly recurseIntoArrays?: boolean | undefined;
|
114 | };
|