ts-gems 3.12.0 → 4.0.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/README.md +114 -2
- package/docs/api/combine.md +48 -0
- package/docs/api/dto.md +115 -0
- package/docs/api/helpers.md +97 -0
- package/docs/api/logical.md +48 -0
- package/docs/api/mutable.md +164 -0
- package/docs/api/non-nullable.md +68 -0
- package/docs/api/nullish.md +66 -0
- package/docs/api/omit-never.md +62 -0
- package/docs/api/omit-undefined.md +60 -0
- package/docs/api/omit.md +99 -0
- package/docs/api/opaque.md +56 -0
- package/docs/api/partial.md +135 -0
- package/docs/api/pick.md +115 -0
- package/docs/api/readonly.md +150 -0
- package/docs/api/required.md +146 -0
- package/docs/api/type-check.md +246 -0
- package/docs/api/types.md +238 -0
- package/docs/api.md +113 -0
- package/docs/logo.svg +43 -0
- package/lib/dto.d.ts +14 -12
- package/lib/helpers.d.ts +16 -15
- package/lib/mutable.d.ts +15 -17
- package/lib/non-nullable.d.ts +31 -23
- package/lib/nullish.d.ts +15 -11
- package/lib/omit-never.d.ts +15 -11
- package/lib/omit-undefined.d.ts +12 -10
- package/lib/omit.d.ts +37 -28
- package/lib/partial.d.ts +12 -11
- package/lib/pick.d.ts +46 -38
- package/lib/readonly.d.ts +91 -77
- package/lib/required.d.ts +91 -75
- package/lib/type-check.d.ts +10 -9
- package/package.json +17 -15
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Nullish
|
|
2
|
+
|
|
3
|
+
Source: [`lib/nullish.d.ts`](../../lib/nullish.d.ts)
|
|
4
|
+
|
|
5
|
+
Makes properties optional **and** nullable (`T[K] | null`) — useful for
|
|
6
|
+
"patch"-style inputs where a client can send `null` to explicitly clear a
|
|
7
|
+
field, as opposed to omitting the key to leave it unchanged. See [the
|
|
8
|
+
`Deep*`/`Deeper*` convention](../api.md#the-deep--deeper-convention) and
|
|
9
|
+
[`PatchDTO`](dto.md#patchdtot-x--never) which builds on `DeeperNullish`.
|
|
10
|
+
|
|
11
|
+
## `NullishObject<T>`
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { NullishObject } from 'ts-gems';
|
|
15
|
+
|
|
16
|
+
interface User {
|
|
17
|
+
name: string;
|
|
18
|
+
age: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type PatchUser = NullishObject<User>;
|
|
22
|
+
// { name?: string | null; age?: number | null }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## `DeepNullish<T>`
|
|
26
|
+
|
|
27
|
+
Like `NullishObject`, but also makes nested object properties optional and
|
|
28
|
+
nullable, recursively. Array-typed properties are left as-is (only wrapped
|
|
29
|
+
in `| null` at their own level).
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import type { DeepNullish } from 'ts-gems';
|
|
33
|
+
|
|
34
|
+
interface Config {
|
|
35
|
+
name: string;
|
|
36
|
+
server: { host: string; port: number };
|
|
37
|
+
tags: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type PatchConfig = DeepNullish<Config>;
|
|
41
|
+
// {
|
|
42
|
+
// name?: string | null;
|
|
43
|
+
// server?: { host?: string | null; port?: number | null } | null;
|
|
44
|
+
// tags?: string[] | null;
|
|
45
|
+
// }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## `DeeperNullish<T>`
|
|
49
|
+
|
|
50
|
+
Like `DeepNullish`, but also recurses into array elements. Tuples are
|
|
51
|
+
preserved as-is (only wrapped in `| null`).
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import type { DeeperNullish } from 'ts-gems';
|
|
55
|
+
|
|
56
|
+
interface Config {
|
|
57
|
+
servers: { host: string }[];
|
|
58
|
+
range: [number, number]; // tuple
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type PatchConfig = DeeperNullish<Config>;
|
|
62
|
+
// {
|
|
63
|
+
// servers?: ({ host?: string | null }[]) | null;
|
|
64
|
+
// range?: [number, number] | null; // tuple - unchanged, just nullable
|
|
65
|
+
// }
|
|
66
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# OmitNever
|
|
2
|
+
|
|
3
|
+
Source: [`lib/omit-never.d.ts`](../../lib/omit-never.d.ts)
|
|
4
|
+
|
|
5
|
+
Removes properties whose value type is `never` — handy after a chain of
|
|
6
|
+
conditional-type transforms leaves some properties resolved to `never`
|
|
7
|
+
(which should behave like "this key doesn't exist"). See [the `Deep*`/
|
|
8
|
+
`Deeper*` convention](../api.md#the-deep--deeper-convention).
|
|
9
|
+
|
|
10
|
+
## `OmitNever<T>`
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import type { OmitNever } from 'ts-gems';
|
|
14
|
+
|
|
15
|
+
type MyType = {
|
|
16
|
+
a: string;
|
|
17
|
+
b: number;
|
|
18
|
+
c?: never;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type Result = OmitNever<MyType>;
|
|
22
|
+
// { a: string; b: number }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## `DeepOmitNever<T>`
|
|
26
|
+
|
|
27
|
+
Like `OmitNever`, but also applies the same removal recursively to nested
|
|
28
|
+
object properties. Array-typed properties are left as-is.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import type { DeepOmitNever } from 'ts-gems';
|
|
32
|
+
|
|
33
|
+
type MyType = {
|
|
34
|
+
a: string;
|
|
35
|
+
nested: { b: number; c: never };
|
|
36
|
+
list: { b: number; c: never }[];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type Result = DeepOmitNever<MyType>;
|
|
40
|
+
// {
|
|
41
|
+
// a: string;
|
|
42
|
+
// nested: { b: number };
|
|
43
|
+
// list: { b: number; c: never }[]; // untouched - it's an array
|
|
44
|
+
// }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## `DeeperOmitNever<T>`
|
|
48
|
+
|
|
49
|
+
Like `DeepOmitNever`, but also recurses into array elements. Tuples are
|
|
50
|
+
preserved as-is.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import type { DeeperOmitNever } from 'ts-gems';
|
|
54
|
+
|
|
55
|
+
type MyType = {
|
|
56
|
+
list: { b: number; c: never }[];
|
|
57
|
+
pair: [string, never];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type Result = DeeperOmitNever<MyType>;
|
|
61
|
+
// { list: { b: number }[]; pair: [string, never] } - tuple untouched
|
|
62
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# OmitUndefined
|
|
2
|
+
|
|
3
|
+
Source: [`lib/omit-undefined.d.ts`](../../lib/omit-undefined.d.ts)
|
|
4
|
+
|
|
5
|
+
Removes properties whose value type is exactly `undefined` (properties
|
|
6
|
+
typed `T | undefined`, i.e. optional-looking-but-not-`?`, are narrowed
|
|
7
|
+
rather than removed unless the whole type collapses to `never`). See
|
|
8
|
+
[the `Deep*`/`Deeper*` convention](../api.md#the-deep--deeper-convention).
|
|
9
|
+
|
|
10
|
+
## `OmitUndefined<T>`
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import type { OmitUndefined } from 'ts-gems';
|
|
14
|
+
|
|
15
|
+
type MyType = {
|
|
16
|
+
a?: number;
|
|
17
|
+
b: string;
|
|
18
|
+
c: undefined;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type Result = OmitUndefined<MyType>;
|
|
22
|
+
// { a?: number; b: string } - `c` (exactly `undefined`) is dropped
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## `DeepOmitUndefined<T>`
|
|
26
|
+
|
|
27
|
+
Like `OmitUndefined`, but also applies the same removal recursively to
|
|
28
|
+
nested object properties. Array-typed properties are left as-is.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import type { DeepOmitUndefined } from 'ts-gems';
|
|
32
|
+
|
|
33
|
+
type MyType = {
|
|
34
|
+
nested: { a?: string; b: undefined };
|
|
35
|
+
list: { a?: string; b: undefined }[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type Result = DeepOmitUndefined<MyType>;
|
|
39
|
+
// {
|
|
40
|
+
// nested: { a?: string };
|
|
41
|
+
// list: { a?: string; b: undefined }[]; // untouched - it's an array
|
|
42
|
+
// }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## `DeeperOmitUndefined<T>`
|
|
46
|
+
|
|
47
|
+
Like `DeepOmitUndefined`, but also recurses into array elements. Tuples are
|
|
48
|
+
preserved as-is.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import type { DeeperOmitUndefined } from 'ts-gems';
|
|
52
|
+
|
|
53
|
+
type MyType = {
|
|
54
|
+
list: { a?: string; b: undefined }[];
|
|
55
|
+
pair: [string, undefined];
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type Result = DeeperOmitUndefined<MyType>;
|
|
59
|
+
// { list: { a?: string }[]; pair: [string, undefined] } - tuple untouched
|
|
60
|
+
```
|
package/docs/api/omit.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Omit
|
|
2
|
+
|
|
3
|
+
Source: [`lib/omit.d.ts`](../../lib/omit.d.ts)
|
|
4
|
+
|
|
5
|
+
Removing properties by key, by kind (function vs. data), or by value type.
|
|
6
|
+
See [Pick](pick.md) for the inverse operations, and [the `Deep*`/`Deeper*`
|
|
7
|
+
convention](../api.md#the-deep--deeper-convention) for `DeepOmitTypes`/
|
|
8
|
+
`DeeperOmitTypes`.
|
|
9
|
+
|
|
10
|
+
## `StrictOmit<T, X>`
|
|
11
|
+
|
|
12
|
+
Like the built-in `Omit<T, K>`, but also drops any remaining key whose value
|
|
13
|
+
type is `never` (after stripping `undefined`) — symmetric with
|
|
14
|
+
[`StrictPick`](pick.md#strictpickt-x), so picking and omitting the same key
|
|
15
|
+
set never disagree about `never`-typed properties.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import type { StrictOmit } from 'ts-gems';
|
|
19
|
+
|
|
20
|
+
interface Row {
|
|
21
|
+
a?: number;
|
|
22
|
+
b: string;
|
|
23
|
+
c: never;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type Result = StrictOmit<Row, 'b'>;
|
|
27
|
+
// { a?: number } - `c` is dropped too, it's `never`
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## `OmitFunctions<T>`
|
|
31
|
+
|
|
32
|
+
Removes every property whose value is a function — the inverse of
|
|
33
|
+
[`PickFunctions`](pick.md#pickfunctionst).
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import type { OmitFunctions } from 'ts-gems';
|
|
37
|
+
|
|
38
|
+
interface Service {
|
|
39
|
+
name: string;
|
|
40
|
+
start(): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type Data = OmitFunctions<Service>;
|
|
44
|
+
// { name: string }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## `OmitTypes<T, X>`
|
|
48
|
+
|
|
49
|
+
Removes properties whose value type is assignable to or from `X`, and
|
|
50
|
+
narrows the remaining properties' types by excluding `X` from their union
|
|
51
|
+
(via `Exclude<T[K], X>`) — the inverse of
|
|
52
|
+
[`PickTypes`](pick.md#picktypest-x).
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import type { OmitTypes } from 'ts-gems';
|
|
56
|
+
|
|
57
|
+
interface Row {
|
|
58
|
+
a: number;
|
|
59
|
+
b: boolean;
|
|
60
|
+
c: string | number | boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type Result = OmitTypes<Row, number>;
|
|
64
|
+
// { b: boolean; c: string | boolean } - `a` is dropped, `number` removed from `c`
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## `DeepOmitTypes<T, X>`
|
|
68
|
+
|
|
69
|
+
Like `OmitTypes`, but also applies the same removal recursively to nested
|
|
70
|
+
object properties. Array-typed properties are left as-is.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import type { DeepOmitTypes } from 'ts-gems';
|
|
74
|
+
|
|
75
|
+
interface Row {
|
|
76
|
+
a: number;
|
|
77
|
+
nested: { a: number; b: string };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type Result = DeepOmitTypes<Row, number>;
|
|
81
|
+
// { nested: { b: string } }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## `DeeperOmitTypes<T, X>`
|
|
85
|
+
|
|
86
|
+
Like `DeepOmitTypes`, but also recurses into array elements. Tuples are
|
|
87
|
+
preserved as-is.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import type { DeeperOmitTypes } from 'ts-gems';
|
|
91
|
+
|
|
92
|
+
interface Row {
|
|
93
|
+
items: { a: number; b: string }[];
|
|
94
|
+
pair: [string, number]; // tuple
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type Result = DeeperOmitTypes<Row, number>;
|
|
98
|
+
// { items: { b: string }[]; pair: [string, number] } - tuple untouched
|
|
99
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Opaque
|
|
2
|
+
|
|
3
|
+
Source: [`lib/opaque.d.ts`](../../lib/opaque.d.ts)
|
|
4
|
+
|
|
5
|
+
## `Opaque<T, N extends string>`
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
type Opaque<T, N extends string> = T & {
|
|
9
|
+
readonly [Symbols.base]: N;
|
|
10
|
+
readonly [Symbols.brand]: N;
|
|
11
|
+
};
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Creates a _branded_ type: structurally still based on `T`, but tagged with a
|
|
15
|
+
unique string literal `N` so that two `Opaque` types built from the same
|
|
16
|
+
base `T` are no longer interchangeable by accident. This is the classic
|
|
17
|
+
["nominal typing" workaround](https://michalzalecki.com/nominal-typing-in-typescript/)
|
|
18
|
+
for a structurally-typed language — useful for IDs, currency amounts, or any
|
|
19
|
+
primitive that shouldn't be swappable with another primitive of the same
|
|
20
|
+
underlying type.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import type { Opaque } from 'ts-gems';
|
|
24
|
+
|
|
25
|
+
type UserId = Opaque<number, 'UserId'>;
|
|
26
|
+
type ProductId = Opaque<number, 'ProductId'>;
|
|
27
|
+
|
|
28
|
+
function getUser(id: UserId) {
|
|
29
|
+
/* ... */
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare const userId: UserId;
|
|
33
|
+
declare const productId: ProductId;
|
|
34
|
+
declare const rawNumber: number;
|
|
35
|
+
|
|
36
|
+
getUser(userId); // ok
|
|
37
|
+
getUser(productId); // type error - different brand, even though both are `number`
|
|
38
|
+
getUser(rawNumber); // type error - a plain number isn't branded at all
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Because `Opaque<T, N>` is an intersection with `T`, a branded value is still
|
|
42
|
+
usable _as_ its base type — the restriction only goes one way:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const id = 1 as UserId;
|
|
46
|
+
const n: number = id; // ok - a UserId structurally satisfies `number`
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
You create a branded value with a type assertion (there's no runtime
|
|
50
|
+
wrapping — the brand only exists at the type level):
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
function toUserId(id: number): UserId {
|
|
54
|
+
return id as UserId;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Partial
|
|
2
|
+
|
|
3
|
+
Source: [`lib/partial.d.ts`](../../lib/partial.d.ts)
|
|
4
|
+
|
|
5
|
+
Makes properties optional. See [the `Deep*`/`Deeper*`
|
|
6
|
+
convention](../api.md#the-deep--deeper-convention) and the runtime
|
|
7
|
+
[`asPartial` cast helpers](helpers.md#runtime-cast-helpers).
|
|
8
|
+
|
|
9
|
+
## `PartialSome<T, K>`
|
|
10
|
+
|
|
11
|
+
Marks only the properties named in `K` as optional; the rest of `T` is
|
|
12
|
+
required exactly as declared.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import type { PartialSome } from 'ts-gems';
|
|
16
|
+
|
|
17
|
+
interface CreateUserInput {
|
|
18
|
+
name: string;
|
|
19
|
+
email: string;
|
|
20
|
+
role: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type UpdateUserInput = PartialSome<CreateUserInput, 'email' | 'role'>;
|
|
24
|
+
// { name: string; email?: string; role?: string }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## `DeepPartial<T>`
|
|
28
|
+
|
|
29
|
+
Like the built-in `Partial<T>`, but also makes nested object properties
|
|
30
|
+
optional, recursively. Array-typed properties are left as-is.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import type { DeepPartial } from 'ts-gems';
|
|
34
|
+
|
|
35
|
+
interface Config {
|
|
36
|
+
name: string;
|
|
37
|
+
server: { host: string; port: number };
|
|
38
|
+
tags: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type PartialConfig = DeepPartial<Config>;
|
|
42
|
+
// {
|
|
43
|
+
// name?: string;
|
|
44
|
+
// server?: { host?: string; port?: number };
|
|
45
|
+
// tags?: string[]; // untouched - it's an array
|
|
46
|
+
// }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## `DeeperPartial<T>`
|
|
50
|
+
|
|
51
|
+
Like `DeepPartial`, but also makes array element properties optional.
|
|
52
|
+
Tuples are left untouched.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import type { DeeperPartial } from 'ts-gems';
|
|
56
|
+
|
|
57
|
+
interface Config {
|
|
58
|
+
servers: { host: string }[];
|
|
59
|
+
range: [number, number]; // tuple
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type PartialConfig = DeeperPartial<Config>;
|
|
63
|
+
// {
|
|
64
|
+
// servers?: { host?: string }[];
|
|
65
|
+
// range?: [number, number]; // tuple - unchanged
|
|
66
|
+
// }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## `OptionalKeys<T>`
|
|
70
|
+
|
|
71
|
+
Returns the union of property names in `T` that are optional.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import type { OptionalKeys } from 'ts-gems';
|
|
75
|
+
|
|
76
|
+
interface Row {
|
|
77
|
+
id: number;
|
|
78
|
+
nickname?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type Optional = OptionalKeys<Row>; // 'nickname'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## `PickOptional<T>` / `OmitOptional<T>`
|
|
85
|
+
|
|
86
|
+
Pick (or omit) only the properties that are optional. Implemented in terms
|
|
87
|
+
of [`OmitRequired`/`PickRequired`](required.md), since "optional" and
|
|
88
|
+
"required" partition every property into exactly two sets.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import type { OmitOptional, PickOptional } from 'ts-gems';
|
|
92
|
+
|
|
93
|
+
interface Row {
|
|
94
|
+
id: number;
|
|
95
|
+
nickname?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type OnlyOptional = PickOptional<Row>; // { nickname?: string }
|
|
99
|
+
type OnlyRequired = OmitOptional<Row>; // { id: number }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## `DeepPickOptional<T>` / `DeepOmitOptional<T>`
|
|
103
|
+
|
|
104
|
+
The deep versions of `PickOptional`/`OmitOptional` — nested objects are
|
|
105
|
+
filtered the same way, recursively. Delegates to
|
|
106
|
+
[`DeepOmitRequired`/`DeepPickRequired`](required.md).
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import type { DeepOmitOptional } from 'ts-gems';
|
|
110
|
+
|
|
111
|
+
interface Row {
|
|
112
|
+
id: number;
|
|
113
|
+
meta: { label?: string; note: string };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
type Required = DeepOmitOptional<Row>;
|
|
117
|
+
// { id: number; meta: { note: string } }
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## `DeeperPickOptional<T>` / `DeeperOmitOptional<T>`
|
|
121
|
+
|
|
122
|
+
Like `DeepPickOptional`/`DeepOmitOptional`, but also recurses into array
|
|
123
|
+
elements. Delegates to
|
|
124
|
+
[`DeeperOmitRequired`/`DeeperPickRequired`](required.md).
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import type { DeeperOmitOptional } from 'ts-gems';
|
|
128
|
+
|
|
129
|
+
interface Row {
|
|
130
|
+
tags: { label?: string; note: string }[];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
type Required = DeeperOmitOptional<Row>;
|
|
134
|
+
// { tags: { note: string }[] }
|
|
135
|
+
```
|
package/docs/api/pick.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Pick
|
|
2
|
+
|
|
3
|
+
Source: [`lib/pick.d.ts`](../../lib/pick.d.ts)
|
|
4
|
+
|
|
5
|
+
Selecting properties by key, by kind (function vs. data), or by value type.
|
|
6
|
+
See [Omit](omit.md) for the inverse operations.
|
|
7
|
+
|
|
8
|
+
## `StrictPick<T, X>`
|
|
9
|
+
|
|
10
|
+
Like the built-in `Pick<T, K>`, but also drops any selected key whose value
|
|
11
|
+
type is `never` (after stripping `undefined`) — consistent with how the rest
|
|
12
|
+
of the library treats `never`-typed properties as "absent".
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import type { StrictPick } from 'ts-gems';
|
|
16
|
+
|
|
17
|
+
interface Row {
|
|
18
|
+
a?: number;
|
|
19
|
+
b: string;
|
|
20
|
+
c: never;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type Result = StrictPick<Row, 'a' | 'c'>;
|
|
24
|
+
// { a?: number } - `c` is dropped, it's `never`
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## `PickFunctions<T>`
|
|
28
|
+
|
|
29
|
+
Keeps only the properties whose value is a function.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import type { PickFunctions } from 'ts-gems';
|
|
33
|
+
|
|
34
|
+
interface Service {
|
|
35
|
+
name: string;
|
|
36
|
+
start(): void;
|
|
37
|
+
stop(): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type Methods = PickFunctions<Service>;
|
|
41
|
+
// { start(): void; stop(): void }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## `PickTypes<T, X>`
|
|
45
|
+
|
|
46
|
+
Keeps properties whose value type is assignable to or from `X` (a
|
|
47
|
+
bidirectional compatibility check, not exact equality — useful for grabbing
|
|
48
|
+
every property that is "roughly" of a given type, unions included).
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import type { PickTypes } from 'ts-gems';
|
|
52
|
+
|
|
53
|
+
interface Row {
|
|
54
|
+
a: number;
|
|
55
|
+
b: string;
|
|
56
|
+
c: string | number | boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type NumberLike = PickTypes<Row, number>;
|
|
60
|
+
// { a: number; c: string | number | boolean }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## `StrictPickTypes<T, X>`
|
|
64
|
+
|
|
65
|
+
Like `PickTypes`, but additionally excludes properties typed `unknown`,
|
|
66
|
+
`any`, or `{}` from matching — useful when you want type-based filtering
|
|
67
|
+
without accidentally sweeping up untyped/loosely-typed properties.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import type { StrictPickTypes } from 'ts-gems';
|
|
71
|
+
|
|
72
|
+
interface Row {
|
|
73
|
+
a: number;
|
|
74
|
+
b: unknown;
|
|
75
|
+
c: any;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type NumberLike = StrictPickTypes<Row, number>;
|
|
79
|
+
// { a: number } - `b` and `c` are excluded even though they're compatible
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## `FunctionKeys<T>` / `NonFunctionKeys<T>`
|
|
83
|
+
|
|
84
|
+
Returns the union of property names whose value is (or isn't) a function.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import type { FunctionKeys, NonFunctionKeys } from 'ts-gems';
|
|
88
|
+
|
|
89
|
+
interface Service {
|
|
90
|
+
name: string;
|
|
91
|
+
start(): void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
type Methods = FunctionKeys<Service>; // 'start'
|
|
95
|
+
type Data = NonFunctionKeys<Service>; // 'name'
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## `KeysOfTypes<T, X>` / `StrictKeysOfTypes<T, X>`
|
|
99
|
+
|
|
100
|
+
Returns the union of property names matching `X`, per the same rules as
|
|
101
|
+
[`PickTypes`](#picktypest-x)/[`StrictPickTypes`](#strictpicktypest-x)
|
|
102
|
+
respectively.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import type { KeysOfTypes, StrictKeysOfTypes } from 'ts-gems';
|
|
106
|
+
|
|
107
|
+
interface Row {
|
|
108
|
+
a: number;
|
|
109
|
+
b: string;
|
|
110
|
+
c: unknown;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
type Keys = KeysOfTypes<Row, number>; // 'a' | 'c' - `unknown` matches everything
|
|
114
|
+
type StrictKeys = StrictKeysOfTypes<Row, number>; // 'a' - `c` (unknown) excluded
|
|
115
|
+
```
|