ts-gems 4.0.2 → 4.0.4
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/lib/dto.d.ts +53 -9
- package/lib/helpers.d.ts +15 -16
- package/lib/mutable.d.ts +13 -3
- package/lib/non-nullable.d.ts +15 -4
- package/lib/nullish.d.ts +14 -3
- package/lib/omit-never.d.ts +19 -5
- package/lib/omit-undefined.d.ts +22 -5
- package/lib/omit.d.ts +19 -5
- package/lib/partial.d.ts +23 -6
- package/lib/readonly.d.ts +51 -14
- package/lib/required.d.ts +57 -15
- package/lib/type-check.d.ts +1 -8
- package/package.json +1 -1
package/lib/dto.d.ts
CHANGED
|
@@ -4,24 +4,68 @@ import { DeeperPartial } from './partial.js';
|
|
|
4
4
|
import { IfNever, IfTuple } from './type-check.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Narrows T to a Data Transfer Object shape: a plain, serializable snapshot
|
|
8
|
+
* of T's data, safe to persist to a database, encode to JSON, or send over
|
|
9
|
+
* an API. It strips whatever only exists in a live JavaScript runtime and
|
|
10
|
+
* cannot survive that round-trip - function properties, and properties
|
|
11
|
+
* whose value or key is a symbol - recursively into nested objects, arrays,
|
|
12
|
+
* and tuples.
|
|
13
|
+
*
|
|
14
|
+
* DTO only removes those non-serializable members. It does not otherwise
|
|
15
|
+
* change a value's mutability, or a property's readonly/optional modifiers
|
|
16
|
+
* - "is this representable as plain data" is orthogonal to "is this
|
|
17
|
+
* mutable/readonly", which is the concern of the
|
|
18
|
+
* Mutable/Readonly/Partial/Required families instead. In particular, a
|
|
19
|
+
* `readonly T[]` property stays a `readonly T[]` after DTO - it is still
|
|
20
|
+
* perfectly serializable, so DTO has no reason to touch it.
|
|
21
|
+
*
|
|
8
22
|
* @template T - The type of the data being transferred.
|
|
23
|
+
* @template X - An extra type unioned into every remaining property's
|
|
24
|
+
* value, useful for tagging every field with a shared marker (e.g. a
|
|
25
|
+
* sentinel for "field not selected"). See docs/api/dto.md.
|
|
9
26
|
*/
|
|
10
27
|
export type DTO<T, X = never> = {
|
|
11
28
|
[
|
|
12
29
|
K in keyof T as K extends symbol
|
|
13
30
|
? never
|
|
14
31
|
: IfNever<Exclude<NonNullable<T[K]>, Function | symbol>, never, K>
|
|
15
|
-
]: IfTuple<NonNullable<T[K]>> extends true
|
|
16
|
-
? NonNullable<T[K]
|
|
32
|
+
]: IfTuple<NonNullable<T[K]>> extends true
|
|
33
|
+
? DTOTuple<NonNullable<T[K]>, X>
|
|
17
34
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
18
|
-
?
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
: // Deep process objects
|
|
23
|
-
DTO<NonNullable<T[K] | X>>;
|
|
35
|
+
? NonNullable<T[K]> extends any[]
|
|
36
|
+
? DTO<U>[] // was a mutable array - stays mutable
|
|
37
|
+
: readonly DTO<U>[] // was a readonly array - DTO doesn't touch mutability
|
|
38
|
+
: DTOValue<T[K], X>;
|
|
24
39
|
};
|
|
25
40
|
|
|
41
|
+
type DTOValue<V, X> =
|
|
42
|
+
IfNoDeepValue<NonNullable<V>> extends true
|
|
43
|
+
? NonNullable<V | X>
|
|
44
|
+
: DTO<NonNullable<V | X>>;
|
|
45
|
+
|
|
46
|
+
type DTOTuple<T, X> = T extends readonly [infer Head, ...infer Rest]
|
|
47
|
+
? IfNever<Exclude<NonNullable<Head>, Function | symbol>> extends true
|
|
48
|
+
? DTOTuple<Rest, X>
|
|
49
|
+
: [DTOValue<Head, X>, ...DTOTuple<Rest, X>]
|
|
50
|
+
: [];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* `DTO<T, X>` with every property (including nested ones and array/tuple
|
|
54
|
+
* elements) made optional. For request bodies where the data is expected to
|
|
55
|
+
* be incomplete - a "create" endpoint where some fields have server-side
|
|
56
|
+
* defaults, or an "update" endpoint where the caller only sends the fields
|
|
57
|
+
* they want to change and omitting a key means "leave it as it is".
|
|
58
|
+
*
|
|
59
|
+
* See `PatchDTO` for the alternative where omitting a key and sending
|
|
60
|
+
* `null` are meant to mean different things.
|
|
61
|
+
*/
|
|
26
62
|
export type PartialDTO<T, X = never> = DeeperPartial<DTO<T, X>>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* `DTO<T, X>` with every property (including nested ones and array/tuple
|
|
66
|
+
* elements) made optional and nullable. For "patch"-style update endpoints
|
|
67
|
+
* that need to distinguish "omit this key, leave the field unchanged" from
|
|
68
|
+
* "send `null` for this key, clear the field" - `PartialDTO` alone cannot
|
|
69
|
+
* express that second case since it never adds `null`.
|
|
70
|
+
*/
|
|
27
71
|
export type PatchDTO<T, X = never> = DeeperNullish<DTO<T, X>>;
|
package/lib/helpers.d.ts
CHANGED
|
@@ -4,32 +4,31 @@ import { Builtin } from './types.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Returns true if T is excluded from deep operations
|
|
6
6
|
*/
|
|
7
|
-
export type IfNoDeepValue<T> =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
export type IfNoDeepValue<T> = T extends Builtin
|
|
8
|
+
? true
|
|
9
|
+
: IfAny<T> extends true
|
|
10
|
+
? T
|
|
11
|
+
: IfTuple<T> extends true
|
|
11
12
|
? true
|
|
12
|
-
:
|
|
13
|
+
: T extends Function
|
|
13
14
|
? true
|
|
14
|
-
: T extends
|
|
15
|
+
: IfClass<T> extends true
|
|
15
16
|
? true
|
|
16
|
-
:
|
|
17
|
+
: T extends Map<any, any>
|
|
17
18
|
? true
|
|
18
|
-
: T extends
|
|
19
|
+
: T extends ReadonlyMap<any, any>
|
|
19
20
|
? true
|
|
20
|
-
: T extends
|
|
21
|
+
: T extends WeakMap<any, any>
|
|
21
22
|
? true
|
|
22
|
-
: T extends
|
|
23
|
+
: T extends Set<any>
|
|
23
24
|
? true
|
|
24
|
-
: T extends
|
|
25
|
+
: T extends ReadonlySet<any>
|
|
25
26
|
? true
|
|
26
|
-
: T extends
|
|
27
|
+
: T extends WeakSet<any>
|
|
27
28
|
? true
|
|
28
|
-
: T extends
|
|
29
|
+
: T extends readonly any[]
|
|
29
30
|
? true
|
|
30
|
-
:
|
|
31
|
-
? true
|
|
32
|
-
: false;
|
|
31
|
+
: false;
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
34
|
* ValuesOf
|
package/lib/mutable.d.ts
CHANGED
|
@@ -40,10 +40,11 @@ export type DeepMutable<T> = {
|
|
|
40
40
|
export type DeeperMutable<T> = {
|
|
41
41
|
-readonly [
|
|
42
42
|
K in keyof T as IfNever<Exclude<T[K], undefined>, never, K>
|
|
43
|
-
]: IfTuple<NonNullable<T[K]>> extends true //
|
|
44
|
-
? T[K]
|
|
43
|
+
]: IfTuple<NonNullable<T[K]>> extends true // Deep process tuples positionally
|
|
44
|
+
? DeeperMutableTuple<NonNullable<T[K]>>
|
|
45
45
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
46
|
-
?
|
|
46
|
+
? // Always mutable - that is DeeperMutable's whole purpose
|
|
47
|
+
null extends T[K]
|
|
47
48
|
? DeeperMutable<U>[] | null
|
|
48
49
|
: DeeperMutable<U>[]
|
|
49
50
|
: // Do not deep process No-Deep values
|
|
@@ -53,6 +54,15 @@ export type DeeperMutable<T> = {
|
|
|
53
54
|
DeeperMutable<Exclude<T[K], undefined>>;
|
|
54
55
|
};
|
|
55
56
|
|
|
57
|
+
type DeeperMutableTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
58
|
+
? [
|
|
59
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
60
|
+
? Head
|
|
61
|
+
: DeeperMutable<NonNullable<Head>>,
|
|
62
|
+
...DeeperMutableTuple<Rest>,
|
|
63
|
+
]
|
|
64
|
+
: [];
|
|
65
|
+
|
|
56
66
|
/**
|
|
57
67
|
* Returns mutable keys of an object
|
|
58
68
|
*/
|
package/lib/non-nullable.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { IfNoDeepValue } from './helpers.js';
|
|
|
2
2
|
import { IfNever, IfNull, IfTuple } from './type-check.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Exclude null and undefined from T
|
|
5
|
+
* Exclude null and undefined from T deeply
|
|
6
6
|
*/
|
|
7
7
|
export type UnNullish<T> = {
|
|
8
8
|
[
|
|
@@ -43,13 +43,24 @@ export type DeeperUnNullish<T> = {
|
|
|
43
43
|
never,
|
|
44
44
|
IfNull<Exclude<T[K], undefined>, never, K>
|
|
45
45
|
>
|
|
46
|
-
]: IfTuple<NonNullable<T[K]>> extends true //
|
|
47
|
-
? NonNullable<T[K]
|
|
46
|
+
]: IfTuple<NonNullable<T[K]>> extends true // Deep process tuples positionally
|
|
47
|
+
? DeeperUnNullishTuple<NonNullable<T[K]>>
|
|
48
48
|
: NonNullable<NonNullable<T[K]>> extends readonly (infer U)[]
|
|
49
|
-
?
|
|
49
|
+
? NonNullable<T[K]> extends any[]
|
|
50
|
+
? DeeperUnNullish<U>[] // was mutable - UnNullish doesn't touch mutability
|
|
51
|
+
: readonly DeeperUnNullish<U>[] // was readonly - preserve that
|
|
50
52
|
: // Do not deep process No-Deep values
|
|
51
53
|
IfNoDeepValue<NonNullable<T[K]>> extends true
|
|
52
54
|
? NonNullable<T[K]>
|
|
53
55
|
: // Deep process objects
|
|
54
56
|
DeeperUnNullish<NonNullable<T[K]>>;
|
|
55
57
|
};
|
|
58
|
+
|
|
59
|
+
type DeeperUnNullishTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
60
|
+
? [
|
|
61
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
62
|
+
? NonNullable<Head>
|
|
63
|
+
: DeeperUnNullish<NonNullable<Head>>,
|
|
64
|
+
...DeeperUnNullishTuple<Rest>,
|
|
65
|
+
]
|
|
66
|
+
: [];
|
package/lib/nullish.d.ts
CHANGED
|
@@ -27,16 +27,27 @@ export type DeepNullish<T> = {
|
|
|
27
27
|
export type DeeperNullish<T> = {
|
|
28
28
|
[K in keyof T as IfNever<Exclude<T[K], undefined>, never, K>]?: IfTuple<
|
|
29
29
|
NonNullable<T[K]>
|
|
30
|
-
> extends true //
|
|
31
|
-
? T[K] | null
|
|
30
|
+
> extends true // Deep process tuples positionally
|
|
31
|
+
? DeeperNullishTuple<NonNullable<T[K]>> | null
|
|
32
32
|
: NonNullable<
|
|
33
33
|
// Deep process arrays
|
|
34
34
|
T[K]
|
|
35
35
|
> extends readonly (infer U)[]
|
|
36
|
-
?
|
|
36
|
+
? NonNullable<T[K]> extends any[]
|
|
37
|
+
? DeeperNullish<U>[] | null // was mutable - DeeperNullish doesn't touch mutability
|
|
38
|
+
: readonly DeeperNullish<U>[] | null // was readonly - preserve that
|
|
37
39
|
: // Do not deep process No-Deep values
|
|
38
40
|
IfNoDeepValue<NonNullable<T[K]>> extends true
|
|
39
41
|
? T[K] | null
|
|
40
42
|
: // Deep process objects
|
|
41
43
|
DeeperNullish<NonNullable<T[K]>> | null;
|
|
42
44
|
};
|
|
45
|
+
|
|
46
|
+
type DeeperNullishTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
47
|
+
? [
|
|
48
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
49
|
+
? Head
|
|
50
|
+
: DeeperNullish<NonNullable<Head>>,
|
|
51
|
+
...DeeperNullishTuple<Rest>,
|
|
52
|
+
]
|
|
53
|
+
: [];
|
package/lib/omit-never.d.ts
CHANGED
|
@@ -43,18 +43,32 @@ export type DeepOmitNever<T> = {
|
|
|
43
43
|
export type DeeperOmitNever<T> = {
|
|
44
44
|
[K in keyof T as IfNever<Exclude<T[K], undefined>, never, K>]: IfTuple<
|
|
45
45
|
NonNullable<T[K]>
|
|
46
|
-
> extends true //
|
|
47
|
-
? T[K]
|
|
46
|
+
> extends true // Deep process tuples positionally
|
|
47
|
+
? DeeperOmitNeverTuple<NonNullable<T[K]>>
|
|
48
48
|
: NonNullable<
|
|
49
49
|
// Deep process arrays
|
|
50
50
|
T[K]
|
|
51
51
|
> extends readonly (infer U)[]
|
|
52
|
-
?
|
|
53
|
-
? DeeperOmitNever
|
|
54
|
-
|
|
52
|
+
? NonNullable<T[K]> extends any[]
|
|
53
|
+
? // was mutable - DeeperOmitNever doesn't touch mutability
|
|
54
|
+
null extends T[K]
|
|
55
|
+
? DeeperOmitNever<U>[] | null
|
|
56
|
+
: DeeperOmitNever<U>[]
|
|
57
|
+
: null extends T[K] // was readonly - preserve that
|
|
58
|
+
? readonly DeeperOmitNever<U>[] | null
|
|
59
|
+
: readonly DeeperOmitNever<U>[]
|
|
55
60
|
: // Do not deep process No-Deep values
|
|
56
61
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
57
62
|
? T[K]
|
|
58
63
|
: // Deep process objects (Exclude, not NonNullable - preserves a `| null` member)
|
|
59
64
|
DeeperOmitNever<Exclude<T[K], undefined>>;
|
|
60
65
|
};
|
|
66
|
+
|
|
67
|
+
type DeeperOmitNeverTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
68
|
+
? [
|
|
69
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
70
|
+
? Head
|
|
71
|
+
: DeeperOmitNever<NonNullable<Head>>,
|
|
72
|
+
...DeeperOmitNeverTuple<Rest>,
|
|
73
|
+
]
|
|
74
|
+
: [];
|
package/lib/omit-undefined.d.ts
CHANGED
|
@@ -27,15 +27,32 @@ export type DeepOmitUndefined<T> = {
|
|
|
27
27
|
export type DeeperOmitUndefined<T> = {
|
|
28
28
|
[K in keyof T as IfNever<Exclude<T[K], undefined>, never, K>]: IfTuple<
|
|
29
29
|
NonNullable<T[K]>
|
|
30
|
-
> extends true //
|
|
31
|
-
? T[K]
|
|
30
|
+
> extends true // Deep process tuples positionally
|
|
31
|
+
? DeeperOmitUndefinedTuple<NonNullable<T[K]>>
|
|
32
32
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
33
|
-
?
|
|
34
|
-
? DeeperOmitUndefined
|
|
35
|
-
|
|
33
|
+
? NonNullable<T[K]> extends any[]
|
|
34
|
+
? // was mutable - DeeperOmitUndefined doesn't touch mutability
|
|
35
|
+
null extends T[K]
|
|
36
|
+
? DeeperOmitUndefined<U>[] | null
|
|
37
|
+
: DeeperOmitUndefined<U>[]
|
|
38
|
+
: null extends T[K] // was readonly - preserve that
|
|
39
|
+
? readonly DeeperOmitUndefined<U>[] | null
|
|
40
|
+
: readonly DeeperOmitUndefined<U>[]
|
|
36
41
|
: // Do not deep process No-Deep values
|
|
37
42
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
38
43
|
? T[K]
|
|
39
44
|
: // Deep process objects (Exclude, not NonNullable - preserves a `| null` member)
|
|
40
45
|
DeeperOmitUndefined<Exclude<T[K], undefined>>;
|
|
41
46
|
};
|
|
47
|
+
|
|
48
|
+
type DeeperOmitUndefinedTuple<T> = T extends readonly [
|
|
49
|
+
infer Head,
|
|
50
|
+
...infer Rest,
|
|
51
|
+
]
|
|
52
|
+
? [
|
|
53
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
54
|
+
? Head
|
|
55
|
+
: DeeperOmitUndefined<NonNullable<Head>>,
|
|
56
|
+
...DeeperOmitUndefinedTuple<Rest>,
|
|
57
|
+
]
|
|
58
|
+
: [];
|
package/lib/omit.d.ts
CHANGED
|
@@ -54,17 +54,31 @@ export type DeepOmitTypes<T, X> = {
|
|
|
54
54
|
export type DeeperOmitTypes<T, X> = {
|
|
55
55
|
[K in keyof T as IfNever<Exclude<T[K], undefined | X>, never, K>]: IfTuple<
|
|
56
56
|
NonNullable<T[K]>
|
|
57
|
-
> extends true //
|
|
58
|
-
?
|
|
57
|
+
> extends true // Deep process tuples positionally
|
|
58
|
+
? DeeperOmitTypesTuple<NonNullable<T[K]>, X>
|
|
59
59
|
: NonNullable<
|
|
60
60
|
// Deep process arrays // Do not deep process No-Deep values
|
|
61
61
|
T[K]
|
|
62
62
|
> extends readonly (infer U)[]
|
|
63
|
-
?
|
|
64
|
-
? DeeperOmitTypes
|
|
65
|
-
|
|
63
|
+
? NonNullable<T[K]> extends any[]
|
|
64
|
+
? // was mutable - DeeperOmitTypes doesn't touch mutability
|
|
65
|
+
null extends T[K]
|
|
66
|
+
? DeeperOmitTypes<U, X>[] | null
|
|
67
|
+
: DeeperOmitTypes<U, X>[]
|
|
68
|
+
: null extends T[K] // was readonly - preserve that
|
|
69
|
+
? readonly DeeperOmitTypes<U, X>[] | null
|
|
70
|
+
: readonly DeeperOmitTypes<U, X>[]
|
|
66
71
|
: IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
67
72
|
? Exclude<T[K], X>
|
|
68
73
|
: // Deep process objects (Exclude, not NonNullable - preserves a `| null` member)
|
|
69
74
|
DeeperOmitTypes<Exclude<T[K], undefined>, X>;
|
|
70
75
|
};
|
|
76
|
+
|
|
77
|
+
type DeeperOmitTypesTuple<T, X> = T extends readonly [infer Head, ...infer Rest]
|
|
78
|
+
? [
|
|
79
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
80
|
+
? Exclude<Head, X>
|
|
81
|
+
: DeeperOmitTypes<NonNullable<Head>, X>,
|
|
82
|
+
...DeeperOmitTypesTuple<Rest, X>,
|
|
83
|
+
]
|
|
84
|
+
: [];
|
package/lib/partial.d.ts
CHANGED
|
@@ -34,12 +34,20 @@ export type DeepPartial<T> = {
|
|
|
34
34
|
export type DeeperPartial<T> = {
|
|
35
35
|
[K in keyof T as IfNever<Exclude<T[K], undefined>, never, K>]?: IfTuple<
|
|
36
36
|
NonNullable<T[K]>
|
|
37
|
-
> extends true //
|
|
38
|
-
? T[K]
|
|
39
|
-
: NonNullable<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
> extends true // Deep process tuples positionally
|
|
38
|
+
? DeeperPartialTuple<NonNullable<T[K]>>
|
|
39
|
+
: NonNullable<
|
|
40
|
+
// Deep process arrays
|
|
41
|
+
T[K]
|
|
42
|
+
> extends readonly (infer U)[]
|
|
43
|
+
? NonNullable<T[K]> extends any[]
|
|
44
|
+
? // was mutable - DeeperPartial doesn't touch mutability
|
|
45
|
+
null extends T[K]
|
|
46
|
+
? DeeperPartial<U>[] | null
|
|
47
|
+
: DeeperPartial<U>[]
|
|
48
|
+
: null extends T[K] // was readonly - preserve that
|
|
49
|
+
? readonly DeeperPartial<U>[] | null
|
|
50
|
+
: readonly DeeperPartial<U>[]
|
|
43
51
|
: // Do not deep process No-Deep values
|
|
44
52
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
45
53
|
? T[K]
|
|
@@ -47,6 +55,15 @@ export type DeeperPartial<T> = {
|
|
|
47
55
|
DeeperPartial<Exclude<T[K], undefined>>;
|
|
48
56
|
};
|
|
49
57
|
|
|
58
|
+
type DeeperPartialTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
59
|
+
? [
|
|
60
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
61
|
+
? Head
|
|
62
|
+
: DeeperPartial<NonNullable<Head>>,
|
|
63
|
+
...DeeperPartialTuple<Rest>,
|
|
64
|
+
]
|
|
65
|
+
: [];
|
|
66
|
+
|
|
50
67
|
/**
|
|
51
68
|
* OptionalKeys
|
|
52
69
|
* @desc Returns optional keys of an object
|
package/lib/readonly.d.ts
CHANGED
|
@@ -26,12 +26,12 @@ export type DeepReadonly<T> = {
|
|
|
26
26
|
export type DeeperReadonly<T> = {
|
|
27
27
|
readonly [
|
|
28
28
|
K in keyof T as IfNever<Exclude<T[K], undefined>, never, K>
|
|
29
|
-
]: IfTuple<NonNullable<T[K]>> extends true //
|
|
30
|
-
? T[K]
|
|
29
|
+
]: IfTuple<NonNullable<T[K]>> extends true // Deep process tuples positionally
|
|
30
|
+
? readonly [...DeeperReadonlyTuple<NonNullable<T[K]>>]
|
|
31
31
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
32
32
|
? null extends T[K] // Preserve a `| null` member lost by NonNullable above
|
|
33
|
-
? DeeperReadonly<U>[] | null
|
|
34
|
-
: DeeperReadonly<U>[]
|
|
33
|
+
? readonly DeeperReadonly<U>[] | null // Always readonly - that is DeeperReadonly's whole purpose
|
|
34
|
+
: readonly DeeperReadonly<U>[]
|
|
35
35
|
: // Do not deep process No-Deep values
|
|
36
36
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
37
37
|
? T[K]
|
|
@@ -39,6 +39,15 @@ export type DeeperReadonly<T> = {
|
|
|
39
39
|
DeeperReadonly<Exclude<T[K], undefined>>;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
type DeeperReadonlyTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
43
|
+
? [
|
|
44
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
45
|
+
? Head
|
|
46
|
+
: DeeperReadonly<NonNullable<Head>>,
|
|
47
|
+
...DeeperReadonlyTuple<Rest>,
|
|
48
|
+
]
|
|
49
|
+
: [];
|
|
50
|
+
|
|
42
51
|
/**
|
|
43
52
|
* Returns readonly keys of an object
|
|
44
53
|
*/
|
|
@@ -127,12 +136,17 @@ export type DeeperPickReadonly<T> = {
|
|
|
127
136
|
> extends true
|
|
128
137
|
? never
|
|
129
138
|
: K
|
|
130
|
-
]: IfTuple<NonNullable<T[K]>> extends true //
|
|
131
|
-
? T[K]
|
|
139
|
+
]: IfTuple<NonNullable<T[K]>> extends true // Deep process tuples positionally
|
|
140
|
+
? DeeperPickReadonlyTuple<NonNullable<T[K]>>
|
|
132
141
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
133
|
-
?
|
|
134
|
-
? DeeperPickReadonly
|
|
135
|
-
|
|
142
|
+
? NonNullable<T[K]> extends any[]
|
|
143
|
+
? // was mutable - DeeperPickReadonly doesn't touch mutability, unlike DeeperReadonly
|
|
144
|
+
null extends T[K]
|
|
145
|
+
? DeeperPickReadonly<U>[] | null
|
|
146
|
+
: DeeperPickReadonly<U>[]
|
|
147
|
+
: null extends T[K] // was readonly - preserve that
|
|
148
|
+
? readonly DeeperPickReadonly<U>[] | null
|
|
149
|
+
: readonly DeeperPickReadonly<U>[]
|
|
136
150
|
: // Do not deep process No-Deep values
|
|
137
151
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
138
152
|
? T[K]
|
|
@@ -140,6 +154,15 @@ export type DeeperPickReadonly<T> = {
|
|
|
140
154
|
DeeperPickReadonly<Exclude<T[K], undefined>>;
|
|
141
155
|
};
|
|
142
156
|
|
|
157
|
+
type DeeperPickReadonlyTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
158
|
+
? [
|
|
159
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
160
|
+
? Head
|
|
161
|
+
: DeeperPickReadonly<NonNullable<Head>>,
|
|
162
|
+
...DeeperPickReadonlyTuple<Rest>,
|
|
163
|
+
]
|
|
164
|
+
: [];
|
|
165
|
+
|
|
143
166
|
/**
|
|
144
167
|
* Pick all readonly properties in T deeply including arrays
|
|
145
168
|
*/
|
|
@@ -153,15 +176,29 @@ export type DeeperOmitReadonly<T> = {
|
|
|
153
176
|
> extends true
|
|
154
177
|
? never
|
|
155
178
|
: K
|
|
156
|
-
]: IfTuple<NonNullable<T[K]>> extends true //
|
|
157
|
-
? T[K]
|
|
179
|
+
]: IfTuple<NonNullable<T[K]>> extends true // Deep process tuples positionally
|
|
180
|
+
? DeeperOmitReadonlyTuple<NonNullable<T[K]>>
|
|
158
181
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
159
|
-
?
|
|
160
|
-
? DeeperOmitReadonly
|
|
161
|
-
|
|
182
|
+
? NonNullable<T[K]> extends any[]
|
|
183
|
+
? // was mutable - DeeperOmitReadonly doesn't touch mutability, unlike DeeperReadonly
|
|
184
|
+
null extends T[K]
|
|
185
|
+
? DeeperOmitReadonly<U>[] | null
|
|
186
|
+
: DeeperOmitReadonly<U>[]
|
|
187
|
+
: null extends T[K] // was readonly - preserve that
|
|
188
|
+
? readonly DeeperOmitReadonly<U>[] | null
|
|
189
|
+
: readonly DeeperOmitReadonly<U>[]
|
|
162
190
|
: // Do not deep process No-Deep values
|
|
163
191
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
164
192
|
? T[K]
|
|
165
193
|
: // Deep process objects (Exclude, not NonNullable - preserves a `| null` member)
|
|
166
194
|
DeeperOmitReadonly<Exclude<T[K], undefined>>;
|
|
167
195
|
};
|
|
196
|
+
|
|
197
|
+
type DeeperOmitReadonlyTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
198
|
+
? [
|
|
199
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
200
|
+
? Head
|
|
201
|
+
: DeeperOmitReadonly<NonNullable<Head>>,
|
|
202
|
+
...DeeperOmitReadonlyTuple<Rest>,
|
|
203
|
+
]
|
|
204
|
+
: [];
|
package/lib/required.d.ts
CHANGED
|
@@ -26,12 +26,17 @@ export type DeepRequired<T> = {
|
|
|
26
26
|
export type DeeperRequired<T> = {
|
|
27
27
|
[K in keyof T as IfNever<Exclude<T[K], undefined>, never, K>]-?: IfTuple<
|
|
28
28
|
NonNullable<T[K]>
|
|
29
|
-
> extends true //
|
|
30
|
-
?
|
|
29
|
+
> extends true // Deep process tuples positionally
|
|
30
|
+
? DeeperRequiredTuple<NonNullable<T[K]>>
|
|
31
31
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
32
|
-
?
|
|
33
|
-
? DeeperRequired
|
|
34
|
-
|
|
32
|
+
? NonNullable<T[K]> extends any[]
|
|
33
|
+
? // was mutable - DeeperRequired doesn't touch mutability
|
|
34
|
+
null extends T[K]
|
|
35
|
+
? DeeperRequired<U>[] | null
|
|
36
|
+
: DeeperRequired<U>[]
|
|
37
|
+
: null extends T[K] // was readonly - preserve that
|
|
38
|
+
? readonly DeeperRequired<U>[] | null
|
|
39
|
+
: readonly DeeperRequired<U>[]
|
|
35
40
|
: // Do not deep process No-Deep values
|
|
36
41
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
37
42
|
? Exclude<T[K], undefined>
|
|
@@ -39,6 +44,15 @@ export type DeeperRequired<T> = {
|
|
|
39
44
|
DeeperRequired<Exclude<T[K], undefined>>;
|
|
40
45
|
};
|
|
41
46
|
|
|
47
|
+
type DeeperRequiredTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
48
|
+
? [
|
|
49
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
50
|
+
? Exclude<Head, undefined>
|
|
51
|
+
: DeeperRequired<NonNullable<Head>>,
|
|
52
|
+
...DeeperRequiredTuple<Rest>,
|
|
53
|
+
]
|
|
54
|
+
: [];
|
|
55
|
+
|
|
42
56
|
/**
|
|
43
57
|
* RequiredKeys
|
|
44
58
|
* @desc Returns required keys of an object
|
|
@@ -128,12 +142,17 @@ export type DeeperPickRequired<T> = {
|
|
|
128
142
|
> extends true
|
|
129
143
|
? never
|
|
130
144
|
: K
|
|
131
|
-
]: IfTuple<NonNullable<T[K]>> extends true //
|
|
132
|
-
? T[K]
|
|
145
|
+
]: IfTuple<NonNullable<T[K]>> extends true // Deep process tuples positionally
|
|
146
|
+
? DeeperPickRequiredTuple<NonNullable<T[K]>>
|
|
133
147
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
134
|
-
?
|
|
135
|
-
? DeeperPickRequired
|
|
136
|
-
|
|
148
|
+
? NonNullable<T[K]> extends any[]
|
|
149
|
+
? // was mutable - DeeperPickRequired doesn't touch mutability
|
|
150
|
+
null extends T[K]
|
|
151
|
+
? DeeperPickRequired<U>[] | null
|
|
152
|
+
: DeeperPickRequired<U>[]
|
|
153
|
+
: null extends T[K] // was readonly - preserve that
|
|
154
|
+
? readonly DeeperPickRequired<U>[] | null
|
|
155
|
+
: readonly DeeperPickRequired<U>[]
|
|
137
156
|
: // Do not deep process No-Deep values
|
|
138
157
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
139
158
|
? T[K]
|
|
@@ -141,6 +160,15 @@ export type DeeperPickRequired<T> = {
|
|
|
141
160
|
DeeperPickRequired<Exclude<T[K], undefined>>;
|
|
142
161
|
};
|
|
143
162
|
|
|
163
|
+
type DeeperPickRequiredTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
164
|
+
? [
|
|
165
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
166
|
+
? Head
|
|
167
|
+
: DeeperPickRequired<NonNullable<Head>>,
|
|
168
|
+
...DeeperPickRequiredTuple<Rest>,
|
|
169
|
+
]
|
|
170
|
+
: [];
|
|
171
|
+
|
|
144
172
|
/**
|
|
145
173
|
* Omit all required properties in T deeply including arrays
|
|
146
174
|
*/
|
|
@@ -154,15 +182,29 @@ export type DeeperOmitRequired<T> = {
|
|
|
154
182
|
> extends true
|
|
155
183
|
? never
|
|
156
184
|
: K
|
|
157
|
-
]: IfTuple<NonNullable<T[K]>> extends true //
|
|
158
|
-
? T[K]
|
|
185
|
+
]: IfTuple<NonNullable<T[K]>> extends true // Deep process tuples positionally
|
|
186
|
+
? DeeperOmitRequiredTuple<NonNullable<T[K]>>
|
|
159
187
|
: NonNullable<T[K]> extends readonly (infer U)[] // Deep process arrays
|
|
160
|
-
?
|
|
161
|
-
? DeeperOmitRequired
|
|
162
|
-
|
|
188
|
+
? NonNullable<T[K]> extends any[]
|
|
189
|
+
? // was mutable - DeeperOmitRequired doesn't touch mutability
|
|
190
|
+
null extends T[K]
|
|
191
|
+
? DeeperOmitRequired<U>[] | null
|
|
192
|
+
: DeeperOmitRequired<U>[]
|
|
193
|
+
: null extends T[K] // was readonly - preserve that
|
|
194
|
+
? readonly DeeperOmitRequired<U>[] | null
|
|
195
|
+
: readonly DeeperOmitRequired<U>[]
|
|
163
196
|
: // Do not deep process No-Deep values
|
|
164
197
|
IfNoDeepValue<Exclude<T[K], undefined>> extends true
|
|
165
198
|
? T[K]
|
|
166
199
|
: // Deep process objects (Exclude, not NonNullable - preserves a `| null` member)
|
|
167
200
|
DeeperOmitRequired<Exclude<T[K], undefined>>;
|
|
168
201
|
};
|
|
202
|
+
|
|
203
|
+
type DeeperOmitRequiredTuple<T> = T extends readonly [infer Head, ...infer Rest]
|
|
204
|
+
? [
|
|
205
|
+
IfNoDeepValue<NonNullable<Head>> extends true
|
|
206
|
+
? Head
|
|
207
|
+
: DeeperOmitRequired<NonNullable<Head>>,
|
|
208
|
+
...DeeperOmitRequiredTuple<Rest>,
|
|
209
|
+
]
|
|
210
|
+
: [];
|
package/lib/type-check.d.ts
CHANGED
|
@@ -57,6 +57,7 @@ export type IfTuple<T, Y = true, N = false> =
|
|
|
57
57
|
? N
|
|
58
58
|
: Y
|
|
59
59
|
: N;
|
|
60
|
+
|
|
60
61
|
export type IfTupleOrAny<T, Y = true, N = false> =
|
|
61
62
|
IfAny<T> extends true ? Y : IfTuple<T, Y, N>;
|
|
62
63
|
|
|
@@ -127,14 +128,6 @@ export type IfClassOrAny<T, Y = true, N = false> =
|
|
|
127
128
|
|
|
128
129
|
/**
|
|
129
130
|
* Returns "Y" if "T1" is exactly same with "T2", "N" otherwise
|
|
130
|
-
*
|
|
131
|
-
* The `IfObject<T1> | IfObject<T2>` check below looks like it should be
|
|
132
|
-
* `Or<IfObject<T1>, IfObject<T2>>` (this file's usual pattern), but it is
|
|
133
|
-
* not a bug: it deliberately only takes the EqualsWrapped/object-safe path
|
|
134
|
-
* when BOTH sides are objects. Wrapping a non-object side (e.g. `string`)
|
|
135
|
-
* in `EqualsWrapped` maps over its own keys instead of comparing it as
|
|
136
|
-
* itself, which gives wrong answers - switching this to `Or` breaks
|
|
137
|
-
* multiple cases in test/type-check.spec.ts's `IfEquals` suite.
|
|
138
131
|
*/
|
|
139
132
|
export type IfEquals<T1, T2, Y = true, N = false> =
|
|
140
133
|
IfObject<T1> | IfObject<T2> extends true
|