ts-fortress 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entry-point.mjs +2 -1
- package/dist/entry-point.mjs.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/record/index.d.mts +1 -0
- package/dist/record/index.d.mts.map +1 -1
- package/dist/record/index.mjs +1 -0
- package/dist/record/index.mjs.map +1 -1
- package/dist/record/omit.mjs +2 -2
- package/dist/record/omit.mjs.map +1 -1
- package/dist/record/optional.d.mts +1 -0
- package/dist/record/optional.d.mts.map +1 -1
- package/dist/record/optional.mjs.map +1 -1
- package/dist/record/partial.mjs +2 -2
- package/dist/record/partial.mjs.map +1 -1
- package/dist/record/pick.mjs +2 -2
- package/dist/record/pick.mjs.map +1 -1
- package/dist/record/required.d.mts +22 -0
- package/dist/record/required.d.mts.map +1 -0
- package/dist/record/required.mjs +33 -0
- package/dist/record/required.mjs.map +1 -0
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/to-union-string.d.mts +1 -0
- package/dist/utils/to-union-string.d.mts.map +1 -1
- package/dist/utils/to-union-string.mjs +4 -3
- package/dist/utils/to-union-string.mjs.map +1 -1
- package/package.json +1 -1
- package/src/compose/intersection.test.mts +10 -11
- package/src/compose/merge-records.test.mts +2 -3
- package/src/compose/union.test.mts +2 -3
- package/src/record/index.mts +1 -0
- package/src/record/omit.mts +2 -2
- package/src/record/optional.mts +5 -0
- package/src/record/partial.mts +3 -3
- package/src/record/pick.mts +2 -2
- package/src/record/required.mts +246 -0
- package/src/record/required.test.mts +600 -0
- package/src/utils/to-union-string.mts +5 -2
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { expectType, Obj } from 'ts-data-forge';
|
|
2
|
+
import { type RecordType, type Type } from '../type.mjs';
|
|
3
|
+
import { toUnionKeyString } from '../utils/index.mjs';
|
|
4
|
+
import {
|
|
5
|
+
isOptionalProperty,
|
|
6
|
+
type OptionalPropertyType,
|
|
7
|
+
type RequiredPropertyType,
|
|
8
|
+
} from './optional.mjs';
|
|
9
|
+
import { record } from './record.mjs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a Required type. If keysToBeRequired is set, only those keys are
|
|
13
|
+
* made required, otherwise, all properties are made required.
|
|
14
|
+
*/
|
|
15
|
+
export const required = <
|
|
16
|
+
const R extends ReadonlyRecord<string, Type<unknown>>,
|
|
17
|
+
const KeysToBeRequired extends NonEmptyArray<keyof R & string>,
|
|
18
|
+
>(
|
|
19
|
+
recordType: RecordType<R>,
|
|
20
|
+
options?: PartialReadonly<{
|
|
21
|
+
keysToBeRequired: KeysToBeRequired;
|
|
22
|
+
typeName: string;
|
|
23
|
+
|
|
24
|
+
/** @default true */
|
|
25
|
+
allowExcessProperties: boolean;
|
|
26
|
+
}>,
|
|
27
|
+
): RequiredType<R, KeysToBeRequired> => {
|
|
28
|
+
const typeNameFilled: string =
|
|
29
|
+
options?.typeName ??
|
|
30
|
+
(options?.keysToBeRequired === undefined
|
|
31
|
+
? `Required<${recordType.typeName}>`
|
|
32
|
+
: `PartiallyRequired<${recordType.typeName}, ${toUnionKeyString(options.keysToBeRequired)}>`);
|
|
33
|
+
|
|
34
|
+
const keysToBeRequired: ReadonlySet<string> = new Set(
|
|
35
|
+
options?.keysToBeRequired ?? Object.keys(recordType.shape),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const requiredShape =
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
40
|
+
Object.fromEntries(
|
|
41
|
+
Object.entries(recordType.shape).map(
|
|
42
|
+
([k, v]) => [k, keysToBeRequired.has(k) ? makeRequired(v) : v] as const,
|
|
43
|
+
),
|
|
44
|
+
) satisfies ReadonlyRecord<string, Type<unknown>> as RequiredTypeShape<
|
|
45
|
+
R,
|
|
46
|
+
KeysToBeRequired
|
|
47
|
+
>;
|
|
48
|
+
|
|
49
|
+
return record(requiredShape, {
|
|
50
|
+
typeName: typeNameFilled,
|
|
51
|
+
allowExcessProperties:
|
|
52
|
+
options?.allowExcessProperties ?? recordType.allowExcessProperties,
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Makes an optional property required by removing the optional flag.
|
|
58
|
+
*/
|
|
59
|
+
const makeRequired = <T extends Type<unknown>>(
|
|
60
|
+
t: T,
|
|
61
|
+
): RequiredPropertyType<T> =>
|
|
62
|
+
isOptionalProperty(t)
|
|
63
|
+
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
64
|
+
(Obj.omit(t, ['optional']) as RequiredPropertyType<T>)
|
|
65
|
+
: t;
|
|
66
|
+
|
|
67
|
+
type RequiredTypeShape<
|
|
68
|
+
R extends ReadonlyRecord<string, Type<unknown>>,
|
|
69
|
+
KeysToBeRequired extends NonEmptyArray<keyof R & string> | undefined,
|
|
70
|
+
> =
|
|
71
|
+
TypeEq<KeysToBeRequired, undefined> extends true
|
|
72
|
+
? FullyRequiredType<R>
|
|
73
|
+
: PartiallyRequiredType<R, ArrayElement<KeysToBeRequired>>;
|
|
74
|
+
|
|
75
|
+
type FullyRequiredType<R extends ReadonlyRecord<string, Type<unknown>>> = {
|
|
76
|
+
readonly [P in keyof R]: RequiredPropertyType<R[P]>;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
type PartiallyRequiredType<
|
|
80
|
+
R extends ReadonlyRecord<string, Type<unknown>>,
|
|
81
|
+
K extends keyof R,
|
|
82
|
+
> = {
|
|
83
|
+
readonly [P in keyof R]: P extends K ? RequiredPropertyType<R[P]> : R[P];
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type RequiredType<
|
|
87
|
+
R extends ReadonlyRecord<string, Type<unknown>>,
|
|
88
|
+
KeysToBeRequired extends NonEmptyArray<keyof R & string> | undefined,
|
|
89
|
+
> = RecordType<RequiredTypeShape<R, KeysToBeRequired>>;
|
|
90
|
+
|
|
91
|
+
expectType<
|
|
92
|
+
RequiredTypeShape<
|
|
93
|
+
{
|
|
94
|
+
a: OptionalPropertyType<Type<0>>;
|
|
95
|
+
b: Type<1>;
|
|
96
|
+
c: OptionalPropertyType<Type<2>>;
|
|
97
|
+
},
|
|
98
|
+
['a']
|
|
99
|
+
>,
|
|
100
|
+
Readonly<{
|
|
101
|
+
a: Type<0>;
|
|
102
|
+
b: Type<1>;
|
|
103
|
+
c: OptionalPropertyType<Type<2>>;
|
|
104
|
+
}>
|
|
105
|
+
>('=');
|
|
106
|
+
|
|
107
|
+
expectType<
|
|
108
|
+
RecordType<
|
|
109
|
+
Readonly<{
|
|
110
|
+
a: Type<0>;
|
|
111
|
+
b: Type<1>;
|
|
112
|
+
c: Type<2>;
|
|
113
|
+
}>
|
|
114
|
+
>,
|
|
115
|
+
Type<
|
|
116
|
+
Readonly<{
|
|
117
|
+
a: 0;
|
|
118
|
+
b: 1;
|
|
119
|
+
c: 2;
|
|
120
|
+
}>
|
|
121
|
+
> &
|
|
122
|
+
Readonly<{
|
|
123
|
+
shape: Readonly<{
|
|
124
|
+
a: Type<0>;
|
|
125
|
+
b: Type<1>;
|
|
126
|
+
c: Type<2>;
|
|
127
|
+
}>;
|
|
128
|
+
allowExcessProperties: boolean;
|
|
129
|
+
}>
|
|
130
|
+
>('=');
|
|
131
|
+
|
|
132
|
+
expectType<
|
|
133
|
+
RecordType<
|
|
134
|
+
Readonly<{
|
|
135
|
+
a: Type<0>;
|
|
136
|
+
b: Type<1>;
|
|
137
|
+
c: OptionalPropertyType<Type<2>>;
|
|
138
|
+
}>
|
|
139
|
+
>,
|
|
140
|
+
Type<
|
|
141
|
+
Readonly<{
|
|
142
|
+
a: 0;
|
|
143
|
+
b: 1;
|
|
144
|
+
c?: 2;
|
|
145
|
+
}>
|
|
146
|
+
> &
|
|
147
|
+
Readonly<{
|
|
148
|
+
shape: Readonly<{
|
|
149
|
+
a: Type<0>;
|
|
150
|
+
b: Type<1>;
|
|
151
|
+
c: OptionalPropertyType<Type<2>>;
|
|
152
|
+
}>;
|
|
153
|
+
allowExcessProperties: boolean;
|
|
154
|
+
}>
|
|
155
|
+
>('=');
|
|
156
|
+
|
|
157
|
+
expectType<
|
|
158
|
+
RequiredType<
|
|
159
|
+
{
|
|
160
|
+
a: OptionalPropertyType<Type<0>>;
|
|
161
|
+
b: Type<1>;
|
|
162
|
+
c: OptionalPropertyType<Type<2>>;
|
|
163
|
+
},
|
|
164
|
+
['a']
|
|
165
|
+
>,
|
|
166
|
+
Type<
|
|
167
|
+
Readonly<{
|
|
168
|
+
a: 0;
|
|
169
|
+
b: 1;
|
|
170
|
+
c?: 2;
|
|
171
|
+
}>
|
|
172
|
+
> &
|
|
173
|
+
Readonly<{
|
|
174
|
+
shape: Readonly<{
|
|
175
|
+
a: Type<0>;
|
|
176
|
+
b: Type<1>;
|
|
177
|
+
c: OptionalPropertyType<Type<2>>;
|
|
178
|
+
}>;
|
|
179
|
+
allowExcessProperties: boolean;
|
|
180
|
+
}>
|
|
181
|
+
>('=');
|
|
182
|
+
|
|
183
|
+
expectType<
|
|
184
|
+
RequiredType<
|
|
185
|
+
{
|
|
186
|
+
a: OptionalPropertyType<Type<0>>;
|
|
187
|
+
b: OptionalPropertyType<Type<1>>;
|
|
188
|
+
c: Type<2>;
|
|
189
|
+
},
|
|
190
|
+
['a', 'b']
|
|
191
|
+
>,
|
|
192
|
+
Type<
|
|
193
|
+
Readonly<{
|
|
194
|
+
a: 0;
|
|
195
|
+
b: 1;
|
|
196
|
+
c: 2;
|
|
197
|
+
}>
|
|
198
|
+
> &
|
|
199
|
+
Readonly<{
|
|
200
|
+
shape: Readonly<{
|
|
201
|
+
a: Type<0>;
|
|
202
|
+
b: Type<1>;
|
|
203
|
+
c: Type<2>;
|
|
204
|
+
}>;
|
|
205
|
+
allowExcessProperties: boolean;
|
|
206
|
+
}>
|
|
207
|
+
>('=');
|
|
208
|
+
|
|
209
|
+
expectType<
|
|
210
|
+
RequiredType<
|
|
211
|
+
{
|
|
212
|
+
a: OptionalPropertyType<Type<0>>;
|
|
213
|
+
b: OptionalPropertyType<Type<1>>;
|
|
214
|
+
c: OptionalPropertyType<Type<2>>;
|
|
215
|
+
},
|
|
216
|
+
undefined
|
|
217
|
+
>,
|
|
218
|
+
Type<
|
|
219
|
+
Readonly<{
|
|
220
|
+
a: 0;
|
|
221
|
+
b: 1;
|
|
222
|
+
c: 2;
|
|
223
|
+
}>
|
|
224
|
+
> &
|
|
225
|
+
Readonly<{
|
|
226
|
+
shape: Readonly<{
|
|
227
|
+
a: Type<0>;
|
|
228
|
+
b: Type<1>;
|
|
229
|
+
c: Type<2>;
|
|
230
|
+
}>;
|
|
231
|
+
allowExcessProperties: boolean;
|
|
232
|
+
}>
|
|
233
|
+
>('=');
|
|
234
|
+
|
|
235
|
+
expectType<
|
|
236
|
+
RequiredType<
|
|
237
|
+
{
|
|
238
|
+
a: OptionalPropertyType<Type<0>>;
|
|
239
|
+
b: Type<1>;
|
|
240
|
+
c: OptionalPropertyType<Type<2>>;
|
|
241
|
+
},
|
|
242
|
+
// @ts-expect-error key "d" doesn't exist
|
|
243
|
+
['a', 'd']
|
|
244
|
+
>,
|
|
245
|
+
0
|
|
246
|
+
>('!=');
|