@wopjs/cast 0.1.7 → 0.1.8
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 +151 -13
- package/dist/index.d.mts +30 -33
- package/dist/index.d.ts +30 -33
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -3
- package/src/is-to-as.test.ts +462 -4
- package/src/is-to-as.ts +44 -35
package/README.md
CHANGED
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
[](https://wopjs.github.io/cast/coverage/)
|
|
7
7
|
[](https://bundlephobia.com/package/@wopjs/cast)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Type-safe utilities for filtering and coercing `unknown` values in TypeScript.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Three-tier API pattern** (`is`/`to`/`as`) for flexible type filtering
|
|
14
|
+
- **Strong TypeScript type narrowing** that preserves complex types (unions, tuples, readonly arrays)
|
|
15
|
+
- **Zero dependencies** and tree-shakeable
|
|
16
|
+
- **Safe edge case handling** (NaN, null, undefined, circular references)
|
|
10
17
|
|
|
11
18
|
## Install
|
|
12
19
|
|
|
@@ -14,22 +21,153 @@ Filter types from unknown.
|
|
|
14
21
|
npm add @wopjs/cast
|
|
15
22
|
```
|
|
16
23
|
|
|
17
|
-
##
|
|
24
|
+
## API Pattern
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
Every type has up to three functions following a consistent naming pattern:
|
|
27
|
+
|
|
28
|
+
| Pattern | Returns | Use Case |
|
|
29
|
+
| ------- | ---------------- | --------------------------------------------- |
|
|
30
|
+
| `is*` | `boolean` | Type guards for conditional narrowing |
|
|
31
|
+
| `to*` | `T \| undefined` | Optional values, composable with Option types |
|
|
32
|
+
| `as*` | `T` | Always returns valid value with fallback |
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { isNumber, toNumber, asNumber } from "@wopjs/cast";
|
|
36
|
+
|
|
37
|
+
// is* - Type guard for conditionals
|
|
38
|
+
if (isNumber(value)) {
|
|
39
|
+
value; // type narrowed to number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// to* - Returns undefined for invalid input
|
|
43
|
+
const num = toNumber(input); // number | undefined
|
|
44
|
+
|
|
45
|
+
// as* - Always returns a number (0 as fallback)
|
|
46
|
+
const safeNum = asNumber(input); // number
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Type Narrowing
|
|
50
|
+
|
|
51
|
+
The library preserves and correctly narrows complex TypeScript types:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { isArray, toArray, isTruthy } from "@wopjs/cast";
|
|
55
|
+
|
|
56
|
+
// Preserves array element types
|
|
57
|
+
const arr: string[] = ["a", "b"];
|
|
58
|
+
if (isArray(arr)) {
|
|
59
|
+
arr; // still string[], not unknown[]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Extracts from unions
|
|
63
|
+
const value: string | string[] = getData();
|
|
64
|
+
if (isArray(value)) {
|
|
65
|
+
value; // narrowed to string[]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Preserves tuples and readonly arrays
|
|
69
|
+
const tuple: [string, number] = ["a", 1];
|
|
70
|
+
const result = toArray(tuple); // [string, number] | undefined
|
|
71
|
+
|
|
72
|
+
// Excludes falsy types
|
|
73
|
+
const val: string | null | undefined = "hello";
|
|
74
|
+
if (isTruthy(val)) {
|
|
75
|
+
val; // narrowed to string
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Available Functions
|
|
80
|
+
|
|
81
|
+
### Booleans
|
|
82
|
+
|
|
83
|
+
| Function | Description |
|
|
84
|
+
| ----------- | -------------------------------------------- |
|
|
85
|
+
| `isTrue` | Returns `true` if value is exactly `true` |
|
|
86
|
+
| `toTrue` | Returns `true` or `undefined` |
|
|
87
|
+
| `asTrue` | Returns `true` or `false` |
|
|
88
|
+
| `isTruthy` | Returns `true` if `Boolean(x)` is `true` |
|
|
89
|
+
| `toTruthy` | Returns truthy value or `undefined` |
|
|
90
|
+
| `isFalsy` | Returns `true` if `Boolean(x)` is `false` |
|
|
91
|
+
| `toFalsy` | Returns falsy value or `undefined` |
|
|
92
|
+
| `isBoolean` | Returns `true` if value is `true` or `false` |
|
|
93
|
+
| `toBoolean` | Returns boolean or `undefined` |
|
|
94
|
+
|
|
95
|
+
### Numbers
|
|
96
|
+
|
|
97
|
+
| Function | Description |
|
|
98
|
+
| ---------- | ----------------------------------------------------- |
|
|
99
|
+
| `isNumber` | Returns `true` if value is a number (excluding `NaN`) |
|
|
100
|
+
| `toNumber` | Returns number or `undefined` |
|
|
101
|
+
| `asNumber` | Returns number or `0` |
|
|
102
|
+
|
|
103
|
+
### Strings
|
|
104
|
+
|
|
105
|
+
| Function | Description |
|
|
106
|
+
| ------------------ | --------------------------------------------- |
|
|
107
|
+
| `isString` | Returns `true` if value is a string |
|
|
108
|
+
| `toString` | Returns string or `undefined` |
|
|
109
|
+
| `asString` | Returns string or `""` |
|
|
110
|
+
| `isNonEmptyString` | Returns `true` if value is a non-empty string |
|
|
111
|
+
| `toNonEmptyString` | Returns non-empty string or `undefined` |
|
|
112
|
+
|
|
113
|
+
### Arrays
|
|
22
114
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
115
|
+
| Function | Description |
|
|
116
|
+
| ----------------- | ----------------------------------------------- |
|
|
117
|
+
| `isArray` | Type guard for arrays (preserves element types) |
|
|
118
|
+
| `toArray` | Returns array or `undefined` |
|
|
119
|
+
| `asArray` | Returns array or `[]` |
|
|
120
|
+
| `isNonEmptyArray` | Type guard for non-empty arrays |
|
|
121
|
+
| `toNonEmptyArray` | Returns non-empty array or `undefined` |
|
|
28
122
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
123
|
+
### Objects
|
|
124
|
+
|
|
125
|
+
| Function | Description |
|
|
126
|
+
| ----------------------- | --------------------------------------------------------------- |
|
|
127
|
+
| `isObject` | Returns `true` for objects (including arrays, excluding `null`) |
|
|
128
|
+
| `toObject` | Returns object or `undefined` |
|
|
129
|
+
| `asObject` | Returns object or `{}` |
|
|
130
|
+
| `isPlainObject` | Returns `true` for plain objects (excluding arrays) |
|
|
131
|
+
| `toPlainObject` | Returns plain object or `undefined` |
|
|
132
|
+
| `asPlainObject` | Returns plain object or `{}` |
|
|
133
|
+
| `isNonEmptyPlainObject` | Returns `true` for objects with at least one key |
|
|
134
|
+
| `toNonEmptyPlainObject` | Returns non-empty object or `undefined` |
|
|
135
|
+
| `isNonEmptyJSONObject` | Returns `true` for objects with non-undefined values |
|
|
136
|
+
| `toNonEmptyJSONObject` | Returns JSON object or `undefined` |
|
|
137
|
+
|
|
138
|
+
### Utilities
|
|
139
|
+
|
|
140
|
+
| Function | Description |
|
|
141
|
+
| --------------------- | ------------------------------------------ |
|
|
142
|
+
| `isDefined` | Returns `true` if value is not `undefined` |
|
|
143
|
+
| `toPlainObjectOf` | Filter object values by type predicate |
|
|
144
|
+
| `toPlainObjectOfTrue` | Filter object to only `true` values |
|
|
145
|
+
| `print` | Safely stringify any value for display |
|
|
146
|
+
|
|
147
|
+
## Usage Example
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import * as c from "@wopjs/cast";
|
|
151
|
+
|
|
152
|
+
// Parsing unknown API response
|
|
153
|
+
function parseUser(data: unknown) {
|
|
154
|
+
const obj = c.asPlainObject(data);
|
|
155
|
+
return {
|
|
156
|
+
name: c.asString(obj.name),
|
|
157
|
+
age: c.toNumber(obj.age), // undefined if not a number
|
|
158
|
+
tags: c.asArray(obj.tags),
|
|
159
|
+
settings: c.toNonEmptyPlainObject(obj.settings),
|
|
160
|
+
};
|
|
32
161
|
}
|
|
162
|
+
|
|
163
|
+
// Filtering object values
|
|
164
|
+
const config = { debug: true, verbose: false, enabled: true };
|
|
165
|
+
c.toPlainObjectOfTrue(config); // { debug: true, enabled: true }
|
|
166
|
+
|
|
167
|
+
// Safe number handling
|
|
168
|
+
c.isNumber(NaN); // false (NaN is excluded)
|
|
169
|
+
c.asNumber(NaN); // 0 (safe fallback)
|
|
170
|
+
c.asNumber("42"); // 0 (not coerced, use parseInt for that)
|
|
33
171
|
```
|
|
34
172
|
|
|
35
173
|
## Publish New Version
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
type _ = undefined;
|
|
2
|
+
/** Map `never` to a different type */
|
|
3
|
+
type MapNeverTo<T, U> = [T, U][T extends any ? 0 : 1];
|
|
2
4
|
/** Returns `true` if `x` is not `undefined`. */
|
|
3
5
|
declare const isDefined: <T>(x: T | undefined) => x is T;
|
|
4
6
|
declare const isTrue: (x: unknown) => x is true;
|
|
@@ -7,12 +9,11 @@ declare const toTrue: (x: unknown) => true | _;
|
|
|
7
9
|
/** Returns `true` if `x` is `true`, otherwise returns `false`. */
|
|
8
10
|
declare const asTrue: (x: unknown) => boolean;
|
|
9
11
|
type Falsy = false | null | undefined | 0 | "";
|
|
10
|
-
|
|
11
|
-
(x: unknown): x is Falsy;
|
|
12
|
-
<T>(x: T): x is Extract<T, Falsy>;
|
|
13
|
-
}
|
|
12
|
+
type ExtractFalsy<T> = MapNeverTo<Extract<T, Falsy>, Falsy>;
|
|
14
13
|
/** Returns `true` if `Boolean(x)` is `false`. */
|
|
15
|
-
declare const isFalsy:
|
|
14
|
+
declare const isFalsy: <T>(x: T) => x is ExtractFalsy<T>;
|
|
15
|
+
/** Returns `x` if `Boolean(x)` is `false`, otherwise returns `undefined`. */
|
|
16
|
+
declare const toFalsy: <T>(x: T) => ExtractFalsy<T> | _;
|
|
16
17
|
/** Returns `true` if `Boolean(x)` is `true`. */
|
|
17
18
|
declare const isTruthy: <T>(x: T) => x is Exclude<T, Falsy>;
|
|
18
19
|
/** Returns `x` if `Boolean(x)` is `true`, otherwise returns `undefined`. */
|
|
@@ -36,53 +37,49 @@ declare const asString: (x: unknown) => string;
|
|
|
36
37
|
declare const isNonEmptyString: (x: unknown) => x is string;
|
|
37
38
|
/** Returns `x` if `x` is a string and not empty, otherwise returns `undefined`. */
|
|
38
39
|
declare const toNonEmptyString: (x: unknown) => string | _;
|
|
39
|
-
type
|
|
40
|
-
|
|
41
|
-
interface IsArray {
|
|
42
|
-
(x: unknown): x is unknown[];
|
|
43
|
-
<T>(x: T): x is T extends readonly unknown[] ? T : never;
|
|
44
|
-
}
|
|
45
|
-
declare const isArray: IsArray;
|
|
40
|
+
type ExtractArray<T> = MapNeverTo<Extract<T, readonly unknown[]>, unknown[]>;
|
|
41
|
+
declare const isArray: <T>(x: T) => x is ExtractArray<T>;
|
|
46
42
|
/** Returns `x` if `x` is an array. */
|
|
47
43
|
declare const toArray: <T>(x: T) => ExtractArray<T> | _;
|
|
44
|
+
/** Returns `x` if `x` is an array, otherwise returns `[]` (empty array). */
|
|
45
|
+
declare const asArray: <T>(x: T) => ExtractArray<T>;
|
|
48
46
|
/** Returns `true` if `x` is an array and has at least one element. */
|
|
49
|
-
declare const isNonEmptyArray:
|
|
47
|
+
declare const isNonEmptyArray: <T>(x: T) => x is ExtractArray<T>;
|
|
50
48
|
/** Returns `x` if `x` is an array and has at least one element, otherwise returns `undefined`. */
|
|
51
49
|
declare const toNonEmptyArray: <T>(x: T) => ExtractArray<T> | _;
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
type ExtractObject<T> = MapNeverTo<Extract<T, object>, object>;
|
|
51
|
+
/** Returns `true` if `x` is an object (including array) and not null. */
|
|
52
|
+
declare const isObject: <T>(x: T) => x is ExtractObject<T>;
|
|
53
|
+
/** Returns `x` if `x` is an object (including array). */
|
|
54
|
+
declare const toObject: <T>(x: T) => ExtractObject<T> | _;
|
|
55
|
+
/** Returns `x` if `x` is an object (including array), otherwise returns `{}` (empty object). */
|
|
56
|
+
declare const asObject: <T>(x: T) => ExtractObject<T>;
|
|
54
57
|
interface PlainObject {
|
|
55
58
|
[key: PropertyKey]: unknown;
|
|
56
59
|
}
|
|
57
|
-
|
|
58
|
-
declare const isObject: (x: unknown) => x is object;
|
|
59
|
-
/** Returns `x` if `x` is an object (including array), otherwise returns `{}` (empty object). */
|
|
60
|
-
declare const asObject: (x: unknown) => object;
|
|
60
|
+
type ExtractPlainObject<T> = MapNeverTo<Exclude<Extract<T, object>, readonly unknown[]>, PlainObject>;
|
|
61
61
|
/** Returns `true` if `x` is a plain object (shallow test), not `null` or array. */
|
|
62
|
-
declare const isPlainObject: (x:
|
|
62
|
+
declare const isPlainObject: <T>(x: T) => x is ExtractPlainObject<T>;
|
|
63
63
|
/** Returns `x` if `x` is a plain object. */
|
|
64
|
-
declare const toPlainObject: (x:
|
|
64
|
+
declare const toPlainObject: <T>(x: T) => ExtractPlainObject<T> | _;
|
|
65
65
|
/** Returns `x` if `x` is a plain object, otherwise returns `{}` (empty object). */
|
|
66
|
-
declare const asPlainObject: (x:
|
|
66
|
+
declare const asPlainObject: <T>(x: T) => ExtractPlainObject<T>;
|
|
67
67
|
/** Returns `true` if `x` is a plain object and has at least one key. */
|
|
68
|
-
declare const isNonEmptyPlainObject: (x:
|
|
68
|
+
declare const isNonEmptyPlainObject: <T>(x: T) => x is ExtractPlainObject<T>;
|
|
69
69
|
/** Returns `x` if `x` is a plain object and has at least one key. */
|
|
70
|
-
declare const toNonEmptyPlainObject: <T
|
|
70
|
+
declare const toNonEmptyPlainObject: <T>(x: T) => ExtractPlainObject<T> | _;
|
|
71
71
|
/** Returns `true` if `x` is a plain object and has at least one key with non-undefined value. */
|
|
72
|
-
declare const isNonEmptyJSONObject: (x:
|
|
72
|
+
declare const isNonEmptyJSONObject: <T>(x: T) => x is ExtractPlainObject<T>;
|
|
73
73
|
/** Returns `x` if `x` is a plain object and has at least one key with non-undefined value, otherwise returns `undefined`. */
|
|
74
|
-
declare const toNonEmptyJSONObject: <T
|
|
74
|
+
declare const toNonEmptyJSONObject: <T>(x: T) => ExtractPlainObject<T> | _;
|
|
75
|
+
type ExtractPlainObjectValue<T> = ExtractPlainObject<T>[keyof ExtractPlainObject<T>];
|
|
75
76
|
/**
|
|
76
77
|
* Creates an object from `x` with keys `k` if `f(x[k])` returns `true`.
|
|
77
78
|
* If `x` is not a plain object, or there's no passed props, returns `undefined`.
|
|
78
79
|
*/
|
|
79
|
-
declare const toPlainObjectOf: <T
|
|
80
|
-
[key: PropertyKey]: T;
|
|
81
|
-
} | _;
|
|
80
|
+
declare const toPlainObjectOf: <T, U extends ExtractPlainObjectValue<T>>(x: T, f: (v: ExtractPlainObjectValue<T>) => v is U) => Record<PropertyKey, U> | _;
|
|
82
81
|
/** Filter props from object `x` whose values are `true`. */
|
|
83
|
-
declare const toPlainObjectOfTrue: (x: unknown) =>
|
|
84
|
-
[key: PropertyKey]: true;
|
|
85
|
-
} | _;
|
|
82
|
+
declare const toPlainObjectOfTrue: (x: unknown) => Record<PropertyKey, true> | _;
|
|
86
83
|
/**
|
|
87
84
|
* Returns `x` if `x` is string, otherwise returns `''` (empty string) if
|
|
88
85
|
* `x` is `null` or `undefined`, otherwise returns `JSON.stringify(x)`.
|
|
@@ -97,4 +94,4 @@ declare const returnsFalse: () => false;
|
|
|
97
94
|
declare const returnsTrue: () => true;
|
|
98
95
|
declare const returnsEmptyString: () => string;
|
|
99
96
|
|
|
100
|
-
export { type ExtractArray, type
|
|
97
|
+
export { type ExtractArray, type ExtractFalsy, type ExtractObject, type ExtractPlainObject, type Falsy, type MapNeverTo, type PlainObject, type _, asArray, asNumber, asObject, asPlainObject, asString, asTrue, isArray, isBoolean, isDefined, isFalsy, isNonEmptyArray, isNonEmptyJSONObject, isNonEmptyPlainObject, isNonEmptyString, isNumber, isObject, isPlainObject, isString, isTrue, isTruthy, noop, print, returnsEmptyString, returnsFalse, returnsNull, returnsTrue, returnsUndefined, toArray, toBoolean, toFalsy, toNonEmptyArray, toNonEmptyJSONObject, toNonEmptyPlainObject, toNonEmptyString, toNumber, toObject, toPlainObject, toPlainObjectOf, toPlainObjectOfTrue, toString, toTrue, toTruthy };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
type _ = undefined;
|
|
2
|
+
/** Map `never` to a different type */
|
|
3
|
+
type MapNeverTo<T, U> = [T, U][T extends any ? 0 : 1];
|
|
2
4
|
/** Returns `true` if `x` is not `undefined`. */
|
|
3
5
|
declare const isDefined: <T>(x: T | undefined) => x is T;
|
|
4
6
|
declare const isTrue: (x: unknown) => x is true;
|
|
@@ -7,12 +9,11 @@ declare const toTrue: (x: unknown) => true | _;
|
|
|
7
9
|
/** Returns `true` if `x` is `true`, otherwise returns `false`. */
|
|
8
10
|
declare const asTrue: (x: unknown) => boolean;
|
|
9
11
|
type Falsy = false | null | undefined | 0 | "";
|
|
10
|
-
|
|
11
|
-
(x: unknown): x is Falsy;
|
|
12
|
-
<T>(x: T): x is Extract<T, Falsy>;
|
|
13
|
-
}
|
|
12
|
+
type ExtractFalsy<T> = MapNeverTo<Extract<T, Falsy>, Falsy>;
|
|
14
13
|
/** Returns `true` if `Boolean(x)` is `false`. */
|
|
15
|
-
declare const isFalsy:
|
|
14
|
+
declare const isFalsy: <T>(x: T) => x is ExtractFalsy<T>;
|
|
15
|
+
/** Returns `x` if `Boolean(x)` is `false`, otherwise returns `undefined`. */
|
|
16
|
+
declare const toFalsy: <T>(x: T) => ExtractFalsy<T> | _;
|
|
16
17
|
/** Returns `true` if `Boolean(x)` is `true`. */
|
|
17
18
|
declare const isTruthy: <T>(x: T) => x is Exclude<T, Falsy>;
|
|
18
19
|
/** Returns `x` if `Boolean(x)` is `true`, otherwise returns `undefined`. */
|
|
@@ -36,53 +37,49 @@ declare const asString: (x: unknown) => string;
|
|
|
36
37
|
declare const isNonEmptyString: (x: unknown) => x is string;
|
|
37
38
|
/** Returns `x` if `x` is a string and not empty, otherwise returns `undefined`. */
|
|
38
39
|
declare const toNonEmptyString: (x: unknown) => string | _;
|
|
39
|
-
type
|
|
40
|
-
|
|
41
|
-
interface IsArray {
|
|
42
|
-
(x: unknown): x is unknown[];
|
|
43
|
-
<T>(x: T): x is T extends readonly unknown[] ? T : never;
|
|
44
|
-
}
|
|
45
|
-
declare const isArray: IsArray;
|
|
40
|
+
type ExtractArray<T> = MapNeverTo<Extract<T, readonly unknown[]>, unknown[]>;
|
|
41
|
+
declare const isArray: <T>(x: T) => x is ExtractArray<T>;
|
|
46
42
|
/** Returns `x` if `x` is an array. */
|
|
47
43
|
declare const toArray: <T>(x: T) => ExtractArray<T> | _;
|
|
44
|
+
/** Returns `x` if `x` is an array, otherwise returns `[]` (empty array). */
|
|
45
|
+
declare const asArray: <T>(x: T) => ExtractArray<T>;
|
|
48
46
|
/** Returns `true` if `x` is an array and has at least one element. */
|
|
49
|
-
declare const isNonEmptyArray:
|
|
47
|
+
declare const isNonEmptyArray: <T>(x: T) => x is ExtractArray<T>;
|
|
50
48
|
/** Returns `x` if `x` is an array and has at least one element, otherwise returns `undefined`. */
|
|
51
49
|
declare const toNonEmptyArray: <T>(x: T) => ExtractArray<T> | _;
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
type ExtractObject<T> = MapNeverTo<Extract<T, object>, object>;
|
|
51
|
+
/** Returns `true` if `x` is an object (including array) and not null. */
|
|
52
|
+
declare const isObject: <T>(x: T) => x is ExtractObject<T>;
|
|
53
|
+
/** Returns `x` if `x` is an object (including array). */
|
|
54
|
+
declare const toObject: <T>(x: T) => ExtractObject<T> | _;
|
|
55
|
+
/** Returns `x` if `x` is an object (including array), otherwise returns `{}` (empty object). */
|
|
56
|
+
declare const asObject: <T>(x: T) => ExtractObject<T>;
|
|
54
57
|
interface PlainObject {
|
|
55
58
|
[key: PropertyKey]: unknown;
|
|
56
59
|
}
|
|
57
|
-
|
|
58
|
-
declare const isObject: (x: unknown) => x is object;
|
|
59
|
-
/** Returns `x` if `x` is an object (including array), otherwise returns `{}` (empty object). */
|
|
60
|
-
declare const asObject: (x: unknown) => object;
|
|
60
|
+
type ExtractPlainObject<T> = MapNeverTo<Exclude<Extract<T, object>, readonly unknown[]>, PlainObject>;
|
|
61
61
|
/** Returns `true` if `x` is a plain object (shallow test), not `null` or array. */
|
|
62
|
-
declare const isPlainObject: (x:
|
|
62
|
+
declare const isPlainObject: <T>(x: T) => x is ExtractPlainObject<T>;
|
|
63
63
|
/** Returns `x` if `x` is a plain object. */
|
|
64
|
-
declare const toPlainObject: (x:
|
|
64
|
+
declare const toPlainObject: <T>(x: T) => ExtractPlainObject<T> | _;
|
|
65
65
|
/** Returns `x` if `x` is a plain object, otherwise returns `{}` (empty object). */
|
|
66
|
-
declare const asPlainObject: (x:
|
|
66
|
+
declare const asPlainObject: <T>(x: T) => ExtractPlainObject<T>;
|
|
67
67
|
/** Returns `true` if `x` is a plain object and has at least one key. */
|
|
68
|
-
declare const isNonEmptyPlainObject: (x:
|
|
68
|
+
declare const isNonEmptyPlainObject: <T>(x: T) => x is ExtractPlainObject<T>;
|
|
69
69
|
/** Returns `x` if `x` is a plain object and has at least one key. */
|
|
70
|
-
declare const toNonEmptyPlainObject: <T
|
|
70
|
+
declare const toNonEmptyPlainObject: <T>(x: T) => ExtractPlainObject<T> | _;
|
|
71
71
|
/** Returns `true` if `x` is a plain object and has at least one key with non-undefined value. */
|
|
72
|
-
declare const isNonEmptyJSONObject: (x:
|
|
72
|
+
declare const isNonEmptyJSONObject: <T>(x: T) => x is ExtractPlainObject<T>;
|
|
73
73
|
/** Returns `x` if `x` is a plain object and has at least one key with non-undefined value, otherwise returns `undefined`. */
|
|
74
|
-
declare const toNonEmptyJSONObject: <T
|
|
74
|
+
declare const toNonEmptyJSONObject: <T>(x: T) => ExtractPlainObject<T> | _;
|
|
75
|
+
type ExtractPlainObjectValue<T> = ExtractPlainObject<T>[keyof ExtractPlainObject<T>];
|
|
75
76
|
/**
|
|
76
77
|
* Creates an object from `x` with keys `k` if `f(x[k])` returns `true`.
|
|
77
78
|
* If `x` is not a plain object, or there's no passed props, returns `undefined`.
|
|
78
79
|
*/
|
|
79
|
-
declare const toPlainObjectOf: <T
|
|
80
|
-
[key: PropertyKey]: T;
|
|
81
|
-
} | _;
|
|
80
|
+
declare const toPlainObjectOf: <T, U extends ExtractPlainObjectValue<T>>(x: T, f: (v: ExtractPlainObjectValue<T>) => v is U) => Record<PropertyKey, U> | _;
|
|
82
81
|
/** Filter props from object `x` whose values are `true`. */
|
|
83
|
-
declare const toPlainObjectOfTrue: (x: unknown) =>
|
|
84
|
-
[key: PropertyKey]: true;
|
|
85
|
-
} | _;
|
|
82
|
+
declare const toPlainObjectOfTrue: (x: unknown) => Record<PropertyKey, true> | _;
|
|
86
83
|
/**
|
|
87
84
|
* Returns `x` if `x` is string, otherwise returns `''` (empty string) if
|
|
88
85
|
* `x` is `null` or `undefined`, otherwise returns `JSON.stringify(x)`.
|
|
@@ -97,4 +94,4 @@ declare const returnsFalse: () => false;
|
|
|
97
94
|
declare const returnsTrue: () => true;
|
|
98
95
|
declare const returnsEmptyString: () => string;
|
|
99
96
|
|
|
100
|
-
export { type ExtractArray, type
|
|
97
|
+
export { type ExtractArray, type ExtractFalsy, type ExtractObject, type ExtractPlainObject, type Falsy, type MapNeverTo, type PlainObject, type _, asArray, asNumber, asObject, asPlainObject, asString, asTrue, isArray, isBoolean, isDefined, isFalsy, isNonEmptyArray, isNonEmptyJSONObject, isNonEmptyPlainObject, isNonEmptyString, isNumber, isObject, isPlainObject, isString, isTrue, isTruthy, noop, print, returnsEmptyString, returnsFalse, returnsNull, returnsTrue, returnsUndefined, toArray, toBoolean, toFalsy, toNonEmptyArray, toNonEmptyJSONObject, toNonEmptyPlainObject, toNonEmptyString, toNumber, toObject, toPlainObject, toPlainObjectOf, toPlainObjectOfTrue, toString, toTrue, toTruthy };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ var isTrue = (x) => x === true;
|
|
|
7
7
|
var toTrue = (x) => x === true ? true : _;
|
|
8
8
|
var asTrue = (x) => x === true ? x : false;
|
|
9
9
|
var isFalsy = (x) => !x;
|
|
10
|
+
var toFalsy = (x) => isFalsy(x) ? x : _;
|
|
10
11
|
var isTruthy = (x) => !!x;
|
|
11
12
|
var toTruthy = (x) => isTruthy(x) ? x : _;
|
|
12
13
|
var isBoolean = (x) => x === true || x === false;
|
|
@@ -21,10 +22,11 @@ var isNonEmptyString = (x) => isString(x) && x !== "";
|
|
|
21
22
|
var toNonEmptyString = (x) => isNonEmptyString(x) ? x : _;
|
|
22
23
|
var isArray = Array.isArray;
|
|
23
24
|
var toArray = (x) => isArray(x) ? x : _;
|
|
25
|
+
var asArray = (x) => isArray(x) ? x : [];
|
|
24
26
|
var isNonEmptyArray = (x) => isArray(x) && x.length > 0;
|
|
25
27
|
var toNonEmptyArray = (x) => isNonEmptyArray(x) ? x : _;
|
|
26
|
-
var asArray = (x) => isArray(x) ? x : [];
|
|
27
28
|
var isObject = (x) => x !== null && typeof x === "object";
|
|
29
|
+
var toObject = (x) => isObject(x) ? x : _;
|
|
28
30
|
var asObject = (x) => isObject(x) ? x : {};
|
|
29
31
|
var isPlainObject = (x) => isObject(x) && !isArray(x);
|
|
30
32
|
var toPlainObject = (x) => isPlainObject(x) ? x : _;
|
|
@@ -98,11 +100,13 @@ exports.returnsTrue = returnsTrue;
|
|
|
98
100
|
exports.returnsUndefined = returnsUndefined;
|
|
99
101
|
exports.toArray = toArray;
|
|
100
102
|
exports.toBoolean = toBoolean;
|
|
103
|
+
exports.toFalsy = toFalsy;
|
|
101
104
|
exports.toNonEmptyArray = toNonEmptyArray;
|
|
102
105
|
exports.toNonEmptyJSONObject = toNonEmptyJSONObject;
|
|
103
106
|
exports.toNonEmptyPlainObject = toNonEmptyPlainObject;
|
|
104
107
|
exports.toNonEmptyString = toNonEmptyString;
|
|
105
108
|
exports.toNumber = toNumber;
|
|
109
|
+
exports.toObject = toObject;
|
|
106
110
|
exports.toPlainObject = toPlainObject;
|
|
107
111
|
exports.toPlainObjectOf = toPlainObjectOf;
|
|
108
112
|
exports.toPlainObjectOfTrue = toPlainObjectOfTrue;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/is-to-as.ts","../src/returns.ts"],"names":[],"mappings":";;;AAAA,IAAM,CAAA,GAAI,MAAA;
|
|
1
|
+
{"version":3,"sources":["../src/is-to-as.ts","../src/returns.ts"],"names":[],"mappings":"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","file":"index.js"}
|
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ var isTrue = (x) => x === true;
|
|
|
5
5
|
var toTrue = (x) => x === true ? true : _;
|
|
6
6
|
var asTrue = (x) => x === true ? x : false;
|
|
7
7
|
var isFalsy = (x) => !x;
|
|
8
|
+
var toFalsy = (x) => isFalsy(x) ? x : _;
|
|
8
9
|
var isTruthy = (x) => !!x;
|
|
9
10
|
var toTruthy = (x) => isTruthy(x) ? x : _;
|
|
10
11
|
var isBoolean = (x) => x === true || x === false;
|
|
@@ -19,10 +20,11 @@ var isNonEmptyString = (x) => isString(x) && x !== "";
|
|
|
19
20
|
var toNonEmptyString = (x) => isNonEmptyString(x) ? x : _;
|
|
20
21
|
var isArray = Array.isArray;
|
|
21
22
|
var toArray = (x) => isArray(x) ? x : _;
|
|
23
|
+
var asArray = (x) => isArray(x) ? x : [];
|
|
22
24
|
var isNonEmptyArray = (x) => isArray(x) && x.length > 0;
|
|
23
25
|
var toNonEmptyArray = (x) => isNonEmptyArray(x) ? x : _;
|
|
24
|
-
var asArray = (x) => isArray(x) ? x : [];
|
|
25
26
|
var isObject = (x) => x !== null && typeof x === "object";
|
|
27
|
+
var toObject = (x) => isObject(x) ? x : _;
|
|
26
28
|
var asObject = (x) => isObject(x) ? x : {};
|
|
27
29
|
var isPlainObject = (x) => isObject(x) && !isArray(x);
|
|
28
30
|
var toPlainObject = (x) => isPlainObject(x) ? x : _;
|
|
@@ -67,6 +69,6 @@ var returnsFalse = () => false;
|
|
|
67
69
|
var returnsTrue = () => true;
|
|
68
70
|
var returnsEmptyString = () => "";
|
|
69
71
|
|
|
70
|
-
export { asArray, asNumber, asObject, asPlainObject, asString, asTrue, isArray, isBoolean, isDefined, isFalsy, isNonEmptyArray, isNonEmptyJSONObject, isNonEmptyPlainObject, isNonEmptyString, isNumber, isObject, isPlainObject, isString, isTrue, isTruthy, noop, print, returnsEmptyString, returnsFalse, returnsNull, returnsTrue, returnsUndefined, toArray, toBoolean, toNonEmptyArray, toNonEmptyJSONObject, toNonEmptyPlainObject, toNonEmptyString, toNumber, toPlainObject, toPlainObjectOf, toPlainObjectOfTrue, toString, toTrue, toTruthy };
|
|
72
|
+
export { asArray, asNumber, asObject, asPlainObject, asString, asTrue, isArray, isBoolean, isDefined, isFalsy, isNonEmptyArray, isNonEmptyJSONObject, isNonEmptyPlainObject, isNonEmptyString, isNumber, isObject, isPlainObject, isString, isTrue, isTruthy, noop, print, returnsEmptyString, returnsFalse, returnsNull, returnsTrue, returnsUndefined, toArray, toBoolean, toFalsy, toNonEmptyArray, toNonEmptyJSONObject, toNonEmptyPlainObject, toNonEmptyString, toNumber, toObject, toPlainObject, toPlainObjectOf, toPlainObjectOfTrue, toString, toTrue, toTruthy };
|
|
71
73
|
//# sourceMappingURL=index.mjs.map
|
|
72
74
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/is-to-as.ts","../src/returns.ts"],"names":[],"mappings":";AAAA,IAAM,CAAA,GAAI,MAAA;
|
|
1
|
+
{"version":3,"sources":["../src/is-to-as.ts","../src/returns.ts"],"names":[],"mappings":"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","file":"index.mjs"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wopjs/cast",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Type-safe utilities for filtering and coercing unknown values in TypeScript.",
|
|
5
5
|
"repository": "wopjs/cast",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -25,7 +25,14 @@
|
|
|
25
25
|
},
|
|
26
26
|
"keywords": [
|
|
27
27
|
"typescript",
|
|
28
|
-
"
|
|
28
|
+
"type-guard",
|
|
29
|
+
"type-narrowing",
|
|
30
|
+
"type-safe",
|
|
31
|
+
"coerce",
|
|
32
|
+
"cast",
|
|
33
|
+
"unknown",
|
|
34
|
+
"validation",
|
|
35
|
+
"filter"
|
|
29
36
|
],
|
|
30
37
|
"maintainers": [
|
|
31
38
|
{
|
package/src/is-to-as.test.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { PlainObject } from ".";
|
|
2
|
+
|
|
1
3
|
import { describe, it, expect } from "vitest";
|
|
2
4
|
|
|
3
5
|
import {
|
|
@@ -7,6 +9,7 @@ import {
|
|
|
7
9
|
asTrue,
|
|
8
10
|
isTruthy,
|
|
9
11
|
isFalsy,
|
|
12
|
+
toFalsy,
|
|
10
13
|
isBoolean,
|
|
11
14
|
toBoolean,
|
|
12
15
|
isNumber,
|
|
@@ -24,6 +27,7 @@ import {
|
|
|
24
27
|
asArray,
|
|
25
28
|
toNonEmptyArray,
|
|
26
29
|
isObject,
|
|
30
|
+
toObject,
|
|
27
31
|
asObject,
|
|
28
32
|
isPlainObject,
|
|
29
33
|
toPlainObject,
|
|
@@ -67,6 +71,33 @@ describe("primitive.ts", () => {
|
|
|
67
71
|
expect(isTruthy(true)).toBe(true);
|
|
68
72
|
expect(isTruthy(false)).toBe(false);
|
|
69
73
|
expect(isTruthy(1)).toBe(true);
|
|
74
|
+
|
|
75
|
+
{
|
|
76
|
+
// Type narrowing - excludes falsy from union
|
|
77
|
+
const val = castType<string | null | undefined>("hello");
|
|
78
|
+
if (isTruthy(val)) {
|
|
79
|
+
const check: string = val;
|
|
80
|
+
expect(check).toBe("hello");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
{
|
|
85
|
+
// Type narrowing - excludes all falsy types
|
|
86
|
+
const val = castType<number | false | null | undefined | "" | 0>(42);
|
|
87
|
+
if (isTruthy(val)) {
|
|
88
|
+
const check: number = val;
|
|
89
|
+
expect(check).toBe(42);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
{
|
|
94
|
+
// Type narrowing - narrows boolean to true
|
|
95
|
+
const val = castType<boolean>(true);
|
|
96
|
+
if (isTruthy(val)) {
|
|
97
|
+
const check: true = val;
|
|
98
|
+
expect(check).toBe(true);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
70
101
|
});
|
|
71
102
|
|
|
72
103
|
it("toTruthy", () => {
|
|
@@ -89,6 +120,71 @@ describe("primitive.ts", () => {
|
|
|
89
120
|
expect(isFalsy(true)).toBe(false);
|
|
90
121
|
expect(isFalsy(false)).toBe(true);
|
|
91
122
|
expect(isFalsy(1)).toBe(false);
|
|
123
|
+
|
|
124
|
+
{
|
|
125
|
+
// Type narrowing - extracts falsy from union
|
|
126
|
+
const val = castType<string | null | undefined>(null);
|
|
127
|
+
if (isFalsy(val)) {
|
|
128
|
+
const check: null | undefined = val;
|
|
129
|
+
expect(check).toBe(null);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
{
|
|
134
|
+
// Type narrowing - extracts all falsy types
|
|
135
|
+
const val = castType<number | false | null | undefined | "" | 0>(0);
|
|
136
|
+
if (isFalsy(val)) {
|
|
137
|
+
const check: false | null | undefined | "" | 0 = val;
|
|
138
|
+
expect(check).toBe(0);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
{
|
|
143
|
+
// Type narrowing - narrows boolean to false
|
|
144
|
+
const val = castType<boolean>(false);
|
|
145
|
+
if (isFalsy(val)) {
|
|
146
|
+
const check: false = val;
|
|
147
|
+
expect(check).toBe(false);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("toFalsy", () => {
|
|
153
|
+
expect(toFalsy(false)).toBe(false);
|
|
154
|
+
expect(toFalsy(null)).toBe(null);
|
|
155
|
+
expect(toFalsy(undefined)).toBe(undefined);
|
|
156
|
+
expect(toFalsy(0)).toBe(0);
|
|
157
|
+
expect(toFalsy("")).toBe("");
|
|
158
|
+
expect(toFalsy(true)).toBe(undefined);
|
|
159
|
+
expect(toFalsy(1)).toBe(undefined);
|
|
160
|
+
expect(toFalsy("hello")).toBe(undefined);
|
|
161
|
+
|
|
162
|
+
{
|
|
163
|
+
// Type narrowing - extracts falsy from union
|
|
164
|
+
const val = castType<string | null | undefined>(null);
|
|
165
|
+
const result = toFalsy(val);
|
|
166
|
+
if (result !== undefined) {
|
|
167
|
+
const check: "" | null = result;
|
|
168
|
+
expect(check).toBe(null);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
{
|
|
173
|
+
// Type narrowing - returns undefined for truthy value
|
|
174
|
+
const val = castType<string | null>("hello");
|
|
175
|
+
const result: "" | null | undefined = toFalsy(val);
|
|
176
|
+
expect(result).toBe(undefined);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
{
|
|
180
|
+
// Type narrowing - extracts falsy from number union
|
|
181
|
+
const val = castType<number | false>(0);
|
|
182
|
+
const result = toFalsy(val);
|
|
183
|
+
if (result !== undefined) {
|
|
184
|
+
const check: 0 | false = result;
|
|
185
|
+
expect(check).toBe(0);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
92
188
|
});
|
|
93
189
|
|
|
94
190
|
it("isBoolean", () => {
|
|
@@ -466,17 +562,28 @@ describe("primitive.ts", () => {
|
|
|
466
562
|
}
|
|
467
563
|
|
|
468
564
|
{
|
|
469
|
-
// Type narrowing - unknown input returns unknown[]
|
|
565
|
+
// Type narrowing - unknown input returns unknown[]
|
|
470
566
|
const arr = castType<unknown>(["a", "b"]);
|
|
471
|
-
|
|
472
|
-
|
|
567
|
+
let result = toNonEmptyArray(arr);
|
|
568
|
+
if (result) {
|
|
569
|
+
// rule out never
|
|
570
|
+
let check = result;
|
|
571
|
+
check = castType<unknown[]>(result);
|
|
572
|
+
expect(check).toEqual(["a", "b"]);
|
|
573
|
+
}
|
|
473
574
|
}
|
|
474
575
|
|
|
475
576
|
{
|
|
476
577
|
// Type narrowing - non-array type (string) returns unknown[] | undefined
|
|
477
578
|
const arr = castType<string>("hello");
|
|
478
|
-
const result
|
|
579
|
+
const result = toNonEmptyArray(arr);
|
|
479
580
|
expect(result).toBe(undefined);
|
|
581
|
+
if (result) {
|
|
582
|
+
// rule out never
|
|
583
|
+
let _check = result;
|
|
584
|
+
_check = castType<unknown[]>(result);
|
|
585
|
+
throw new Error("Unreachable");
|
|
586
|
+
}
|
|
480
587
|
}
|
|
481
588
|
});
|
|
482
589
|
|
|
@@ -484,59 +591,410 @@ describe("primitive.ts", () => {
|
|
|
484
591
|
expect(isObject({})).toBe(true);
|
|
485
592
|
expect(isObject([])).toBe(true);
|
|
486
593
|
expect(isObject(null)).toBe(false);
|
|
594
|
+
|
|
595
|
+
{
|
|
596
|
+
// Type narrowing - preserves object type
|
|
597
|
+
const obj = castType<{ a: string }>({ a: "hello" });
|
|
598
|
+
if (isObject(obj)) {
|
|
599
|
+
const check: { a: string } = obj;
|
|
600
|
+
expect(check).toBe(obj);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
{
|
|
605
|
+
// Type narrowing - extracts object from union
|
|
606
|
+
const obj = castType<string | { a: string }>({ a: "hello" });
|
|
607
|
+
if (isObject(obj)) {
|
|
608
|
+
const check: object = obj;
|
|
609
|
+
expect(check).toEqual({ a: "hello" });
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
{
|
|
614
|
+
// Type narrowing - arrays are objects
|
|
615
|
+
const arr = castType<string[]>(["a", "b"]);
|
|
616
|
+
if (isObject(arr)) {
|
|
617
|
+
const check: string[] = arr;
|
|
618
|
+
expect(check).toBe(arr);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
{
|
|
623
|
+
// Type narrowing - unknown input narrows to object
|
|
624
|
+
const obj = castType<unknown>({ a: 1 });
|
|
625
|
+
if (isObject(obj)) {
|
|
626
|
+
const check: object = obj;
|
|
627
|
+
expect(check).toEqual({ a: 1 });
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
{
|
|
632
|
+
// Type narrowing - null | object union extracts object
|
|
633
|
+
const obj = castType<null | { x: number }>({ x: 42 });
|
|
634
|
+
if (isObject(obj)) {
|
|
635
|
+
const check: { x: number } = obj;
|
|
636
|
+
expect(check).toEqual({ x: 42 });
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
it("toObject", () => {
|
|
642
|
+
expect(toObject({})).toEqual({});
|
|
643
|
+
expect(toObject([])).toEqual([]);
|
|
644
|
+
expect(toObject(null)).toBe(undefined);
|
|
645
|
+
|
|
646
|
+
{
|
|
647
|
+
// Type narrowing - preserves object type
|
|
648
|
+
const obj = castType<{ a: string }>({ a: "hello" });
|
|
649
|
+
const result = toObject(obj);
|
|
650
|
+
if (result) {
|
|
651
|
+
const check: { a: string } = result;
|
|
652
|
+
expect(check).toBe(obj);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
{
|
|
657
|
+
// Type narrowing - extracts object from union
|
|
658
|
+
const obj = castType<string | { a: string }>({ a: "hello" });
|
|
659
|
+
const result = toObject(obj);
|
|
660
|
+
if (result) {
|
|
661
|
+
const check: { a: string } = result;
|
|
662
|
+
expect(check).toEqual({ a: "hello" });
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
{
|
|
667
|
+
// Type narrowing - preserves array (arrays are objects)
|
|
668
|
+
const arr = castType<string[]>(["a", "b"]);
|
|
669
|
+
const result = toObject(arr);
|
|
670
|
+
if (result) {
|
|
671
|
+
const check: string[] = result;
|
|
672
|
+
expect(check).toBe(arr);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
{
|
|
677
|
+
// Type narrowing - unknown input returns object | undefined
|
|
678
|
+
const obj = castType<unknown>({ a: 1 });
|
|
679
|
+
const result: object | undefined = toObject(obj);
|
|
680
|
+
expect(result).toEqual({ a: 1 });
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
{
|
|
684
|
+
// Type narrowing - non-object type (string) returns undefined
|
|
685
|
+
const obj = castType<string>("hello");
|
|
686
|
+
const result: object | undefined = toObject(obj);
|
|
687
|
+
expect(result).toBe(undefined);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
{
|
|
691
|
+
// Type narrowing - null | object union extracts object
|
|
692
|
+
const obj = castType<null | { x: number }>({ x: 42 });
|
|
693
|
+
const result = toObject(obj);
|
|
694
|
+
if (result) {
|
|
695
|
+
const check: { x: number } = result;
|
|
696
|
+
expect(check).toEqual({ x: 42 });
|
|
697
|
+
}
|
|
698
|
+
}
|
|
487
699
|
});
|
|
488
700
|
|
|
489
701
|
it("asObject", () => {
|
|
490
702
|
expect(asObject({})).toEqual({});
|
|
491
703
|
expect(asObject([])).toEqual([]);
|
|
492
704
|
expect(asObject(null)).toEqual({});
|
|
705
|
+
|
|
706
|
+
{
|
|
707
|
+
// Type narrowing - preserves object type
|
|
708
|
+
const obj = castType<{ a: string }>({ a: "hello" });
|
|
709
|
+
const result: { a: string } = asObject(obj);
|
|
710
|
+
expect(result).toBe(obj);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
{
|
|
714
|
+
// Type narrowing - extracts object from union
|
|
715
|
+
const obj = castType<string | { a: string }>({ a: "hello" });
|
|
716
|
+
const result: { a: string } = asObject(obj);
|
|
717
|
+
expect(result).toEqual({ a: "hello" });
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
{
|
|
721
|
+
// Type narrowing - preserves array (arrays are objects)
|
|
722
|
+
const arr = castType<string[]>(["a", "b"]);
|
|
723
|
+
const result: string[] = asObject(arr);
|
|
724
|
+
expect(result).toBe(arr);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
{
|
|
728
|
+
// Type narrowing - unknown input returns object
|
|
729
|
+
const obj = castType<unknown>({ a: 1 });
|
|
730
|
+
const result: object = asObject(obj);
|
|
731
|
+
expect(result).toEqual({ a: 1 });
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
{
|
|
735
|
+
// Type narrowing - non-object type (string) returns object
|
|
736
|
+
const obj = castType<string>("hello");
|
|
737
|
+
const result: object = asObject(obj);
|
|
738
|
+
expect(result).toEqual({});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
{
|
|
742
|
+
// Type narrowing - null | object union extracts object
|
|
743
|
+
const obj = castType<null | { x: number }>({ x: 42 });
|
|
744
|
+
const result: { x: number } = asObject(obj);
|
|
745
|
+
expect(result).toEqual({ x: 42 });
|
|
746
|
+
}
|
|
493
747
|
});
|
|
494
748
|
|
|
495
749
|
it("isPlainObject", () => {
|
|
496
750
|
expect(isPlainObject({})).toBe(true);
|
|
497
751
|
expect(isPlainObject([])).toBe(false);
|
|
498
752
|
expect(isPlainObject(null)).toBe(false);
|
|
753
|
+
|
|
754
|
+
{
|
|
755
|
+
// Type narrowing - unknown input narrows to PlainObject
|
|
756
|
+
const obj = castType<unknown>({ a: 1 });
|
|
757
|
+
if (isPlainObject(obj)) {
|
|
758
|
+
const check: PlainObject = obj;
|
|
759
|
+
expect(check).toEqual({ a: 1 });
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
{
|
|
764
|
+
// Type narrowing - excludes array from union
|
|
765
|
+
const obj = castType<{ a: number } | number[]>({ a: 1 });
|
|
766
|
+
if (isPlainObject(obj)) {
|
|
767
|
+
const check: PlainObject = obj;
|
|
768
|
+
expect(check).toEqual({ a: 1 });
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
{
|
|
773
|
+
// Type narrowing - null | object union extracts PlainObject
|
|
774
|
+
const obj = castType<null | { x: number }>({ x: 42 });
|
|
775
|
+
if (isPlainObject(obj)) {
|
|
776
|
+
const check: { x: number } = obj;
|
|
777
|
+
expect(check).toEqual({ x: 42 });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
499
780
|
});
|
|
500
781
|
|
|
501
782
|
it("toPlainObject", () => {
|
|
502
783
|
expect(toPlainObject({})).toEqual({});
|
|
503
784
|
expect(toPlainObject([])).toBe(undefined);
|
|
504
785
|
expect(toPlainObject(null)).toBe(undefined);
|
|
786
|
+
|
|
787
|
+
{
|
|
788
|
+
// Type narrowing - unknown input returns PlainObject | undefined
|
|
789
|
+
const obj = castType<unknown>({ a: 1 });
|
|
790
|
+
const result: PlainObject | undefined = toPlainObject(obj);
|
|
791
|
+
expect(result).toEqual({ a: 1 });
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
{
|
|
795
|
+
// Type narrowing - array returns undefined
|
|
796
|
+
const arr = castType<number[]>([1, 2]);
|
|
797
|
+
const result: PlainObject | undefined = toPlainObject(arr);
|
|
798
|
+
expect(result).toBe(undefined);
|
|
799
|
+
}
|
|
505
800
|
});
|
|
506
801
|
|
|
507
802
|
it("asPlainObject", () => {
|
|
508
803
|
expect(asPlainObject({})).toEqual({});
|
|
509
804
|
expect(asPlainObject([])).toEqual({});
|
|
510
805
|
expect(asPlainObject(null)).toEqual({});
|
|
806
|
+
|
|
807
|
+
{
|
|
808
|
+
// Type narrowing - unknown input returns PlainObject
|
|
809
|
+
const obj = castType<unknown>({ a: 1 });
|
|
810
|
+
const result: PlainObject = asPlainObject(obj);
|
|
811
|
+
expect(result).toEqual({ a: 1 });
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
{
|
|
815
|
+
// Type narrowing - array returns empty object
|
|
816
|
+
const arr = castType<number[]>([1, 2]);
|
|
817
|
+
const result: PlainObject = asPlainObject(arr);
|
|
818
|
+
expect(result).toEqual({});
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
{
|
|
822
|
+
// Type narrowing - non-object returns empty object
|
|
823
|
+
const val = castType<string>("hello");
|
|
824
|
+
const result: PlainObject = asPlainObject(val);
|
|
825
|
+
expect(result).toEqual({});
|
|
826
|
+
}
|
|
511
827
|
});
|
|
512
828
|
|
|
513
829
|
it("isNonEmptyPlainObject", () => {
|
|
514
830
|
expect(isNonEmptyPlainObject({ a: 1 })).toBe(true);
|
|
515
831
|
expect(isNonEmptyPlainObject({})).toBe(false);
|
|
516
832
|
expect(isNonEmptyPlainObject([])).toBe(false);
|
|
833
|
+
|
|
834
|
+
{
|
|
835
|
+
// Type narrowing - unknown input narrows to PlainObject
|
|
836
|
+
const obj = castType<unknown>({ a: 1 });
|
|
837
|
+
if (isNonEmptyPlainObject(obj)) {
|
|
838
|
+
const check: PlainObject = obj;
|
|
839
|
+
expect(check).toEqual({ a: 1 });
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
{
|
|
844
|
+
// Type narrowing - empty object returns false
|
|
845
|
+
const obj = castType<{ a?: number }>({});
|
|
846
|
+
if (isNonEmptyPlainObject(obj)) {
|
|
847
|
+
const check: PlainObject = obj;
|
|
848
|
+
expect(check).toEqual({});
|
|
849
|
+
} else {
|
|
850
|
+
expect(obj).toEqual({});
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
{
|
|
855
|
+
// Type narrowing - excludes array
|
|
856
|
+
const obj = castType<{ a: number } | number[]>({ a: 1 });
|
|
857
|
+
if (isNonEmptyPlainObject(obj)) {
|
|
858
|
+
const check: PlainObject = obj;
|
|
859
|
+
expect(check).toEqual({ a: 1 });
|
|
860
|
+
}
|
|
861
|
+
}
|
|
517
862
|
});
|
|
518
863
|
|
|
519
864
|
it("toNonEmptyPlainObject", () => {
|
|
520
865
|
expect(toNonEmptyPlainObject({ a: 1 })).toEqual({ a: 1 });
|
|
521
866
|
expect(toNonEmptyPlainObject({})).toBe(undefined);
|
|
867
|
+
|
|
868
|
+
{
|
|
869
|
+
// Type narrowing - preserves object type
|
|
870
|
+
const obj = castType<{ a: number }>({ a: 1 });
|
|
871
|
+
const result = toNonEmptyPlainObject(obj);
|
|
872
|
+
if (result) {
|
|
873
|
+
const check: { a: number } = result;
|
|
874
|
+
expect(check).toEqual({ a: 1 });
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
{
|
|
879
|
+
// Type narrowing - undefined input returns undefined
|
|
880
|
+
const obj = castType<{ a: number } | undefined>(undefined);
|
|
881
|
+
const result: { a: number } | undefined = toNonEmptyPlainObject(obj);
|
|
882
|
+
expect(result).toBe(undefined);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
{
|
|
886
|
+
// Type narrowing - empty object returns undefined
|
|
887
|
+
const obj = castType<{ a?: number }>({});
|
|
888
|
+
const result = toNonEmptyPlainObject(obj);
|
|
889
|
+
expect(result).toBe(undefined);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
{
|
|
893
|
+
// type narrowing - non-object type returns PlainObject | undefined
|
|
894
|
+
const obj = castType<number>(42);
|
|
895
|
+
const result: PlainObject | undefined = toNonEmptyPlainObject(obj);
|
|
896
|
+
expect(result).toBe(undefined);
|
|
897
|
+
}
|
|
522
898
|
});
|
|
523
899
|
|
|
524
900
|
it("isNonEmptyJSONObject", () => {
|
|
525
901
|
expect(isNonEmptyJSONObject({ a: 1 })).toBe(true);
|
|
526
902
|
expect(isNonEmptyJSONObject({})).toBe(false);
|
|
527
903
|
expect(isNonEmptyJSONObject([])).toBe(false);
|
|
904
|
+
expect(isNonEmptyJSONObject({ a: undefined })).toBe(false);
|
|
905
|
+
|
|
906
|
+
{
|
|
907
|
+
// Type narrowing - unknown input narrows to PlainObject
|
|
908
|
+
const obj = castType<unknown>({ a: 1 });
|
|
909
|
+
if (isNonEmptyJSONObject(obj)) {
|
|
910
|
+
const check: PlainObject = obj;
|
|
911
|
+
expect(check).toEqual({ a: 1 });
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
{
|
|
916
|
+
// Type narrowing - object with only undefined values returns false
|
|
917
|
+
const obj = castType<{ a?: number }>({ a: undefined });
|
|
918
|
+
if (isNonEmptyJSONObject(obj)) {
|
|
919
|
+
const check: PlainObject = obj;
|
|
920
|
+
expect(check).toEqual({});
|
|
921
|
+
} else {
|
|
922
|
+
expect(obj).toEqual({ a: undefined });
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
{
|
|
927
|
+
// Type narrowing - excludes array
|
|
928
|
+
const obj = castType<{ a: number } | number[]>({ a: 1 });
|
|
929
|
+
if (isNonEmptyJSONObject(obj)) {
|
|
930
|
+
const check: PlainObject = obj;
|
|
931
|
+
expect(check).toEqual({ a: 1 });
|
|
932
|
+
}
|
|
933
|
+
}
|
|
528
934
|
});
|
|
529
935
|
|
|
530
936
|
it("toNonEmptyJSONObject", () => {
|
|
531
937
|
expect(toNonEmptyJSONObject({ a: 1 })).toEqual({ a: 1 });
|
|
532
938
|
expect(toNonEmptyJSONObject({})).toBe(undefined);
|
|
939
|
+
|
|
940
|
+
{
|
|
941
|
+
// Type narrowing - preserves object type
|
|
942
|
+
const obj = castType<{ a: number }>({ a: 1 });
|
|
943
|
+
const result = toNonEmptyJSONObject(obj);
|
|
944
|
+
if (result) {
|
|
945
|
+
const check: { a: number } = result;
|
|
946
|
+
expect(check).toEqual({ a: 1 });
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
{
|
|
951
|
+
// Type narrowing - undefined input returns undefined
|
|
952
|
+
const obj = castType<{ a: number } | undefined>(undefined);
|
|
953
|
+
const result: { a: number } | undefined = toNonEmptyJSONObject(obj);
|
|
954
|
+
expect(result).toBe(undefined);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
{
|
|
958
|
+
// Type narrowing - object with only undefined values returns undefined
|
|
959
|
+
const obj = castType<{ a: number; b?: string }>({ a: undefined as unknown as number });
|
|
960
|
+
const result = toNonEmptyJSONObject(obj);
|
|
961
|
+
expect(result).toBe(undefined);
|
|
962
|
+
}
|
|
533
963
|
});
|
|
534
964
|
|
|
535
965
|
it("toPlainObjectOf", () => {
|
|
536
966
|
expect(toPlainObjectOf({ a: true, b: false }, isTrue)).toEqual({ a: true });
|
|
967
|
+
// @ts-expect-error type mismatched
|
|
537
968
|
expect(toPlainObjectOf({ a: 1, b: 2 }, isTrue)).toBe(undefined);
|
|
538
969
|
expect(toPlainObjectOf({ a: 1, b: 2 }, isTruthy)).toEqual({ a: 1, b: 2 });
|
|
539
970
|
expect(toPlainObjectOf(undefined, isTrue)).toBe(undefined);
|
|
971
|
+
|
|
972
|
+
{
|
|
973
|
+
// Type narrowing - result type matches predicate
|
|
974
|
+
const obj = castType<{ a: unknown; b: unknown }>({ a: "hello", b: 123 });
|
|
975
|
+
const result = toPlainObjectOf(obj, isString);
|
|
976
|
+
if (result) {
|
|
977
|
+
const check: { [key: PropertyKey]: string } = result;
|
|
978
|
+
expect(check).toEqual({ a: "hello" });
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
{
|
|
983
|
+
// Type narrowing - filters to number type
|
|
984
|
+
const obj = castType<{ a: unknown; b: unknown }>({ a: 1, b: "hello" });
|
|
985
|
+
const result = toPlainObjectOf(obj, isNumber);
|
|
986
|
+
if (result) {
|
|
987
|
+
const check: { [key: PropertyKey]: number } = result;
|
|
988
|
+
expect(check).toEqual({ a: 1 });
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
{
|
|
993
|
+
// Type narrowing - returns undefined when no values match
|
|
994
|
+
const obj = castType<{ a: unknown; b: unknown }>({ a: "hello", b: "world" });
|
|
995
|
+
const result = toPlainObjectOf(obj, isNumber);
|
|
996
|
+
expect(result).toBe(undefined);
|
|
997
|
+
}
|
|
540
998
|
});
|
|
541
999
|
|
|
542
1000
|
it("toPlainObjectOfTrue", () => {
|
package/src/is-to-as.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const _ = undefined;
|
|
2
2
|
export type _ = undefined;
|
|
3
3
|
|
|
4
|
+
/** Map `never` to a different type */
|
|
5
|
+
export type MapNeverTo<T, U> = [T, U][T extends any ? 0 : 1];
|
|
6
|
+
|
|
4
7
|
/** Returns `true` if `x` is not `undefined`. */
|
|
5
8
|
export const isDefined = <T>(x: T | undefined): x is T => x !== _;
|
|
6
9
|
|
|
@@ -14,13 +17,13 @@ export const asTrue = (x: unknown): boolean => (x === true ? x : false);
|
|
|
14
17
|
|
|
15
18
|
export type Falsy = false | null | undefined | 0 | "";
|
|
16
19
|
|
|
17
|
-
export
|
|
18
|
-
(x: unknown): x is Falsy;
|
|
19
|
-
<T>(x: T): x is Extract<T, Falsy>;
|
|
20
|
-
}
|
|
20
|
+
export type ExtractFalsy<T> = MapNeverTo<Extract<T, Falsy>, Falsy>;
|
|
21
21
|
|
|
22
22
|
/** Returns `true` if `Boolean(x)` is `false`. */
|
|
23
|
-
export const isFalsy
|
|
23
|
+
export const isFalsy = <T>(x: T): x is ExtractFalsy<T> => !x;
|
|
24
|
+
|
|
25
|
+
/** Returns `x` if `Boolean(x)` is `false`, otherwise returns `undefined`. */
|
|
26
|
+
export const toFalsy = <T>(x: T): ExtractFalsy<T> | _ => (isFalsy(x) ? x : _);
|
|
24
27
|
|
|
25
28
|
/** Returns `true` if `Boolean(x)` is `true`. */
|
|
26
29
|
export const isTruthy = <T>(x: T): x is Exclude<T, Falsy> => !!x;
|
|
@@ -57,74 +60,80 @@ export const isNonEmptyString = (x: unknown): x is string => isString(x) && x !=
|
|
|
57
60
|
/** Returns `x` if `x` is a string and not empty, otherwise returns `undefined`. */
|
|
58
61
|
export const toNonEmptyString = (x: unknown): string | _ => (isNonEmptyString(x) ? x : _);
|
|
59
62
|
|
|
60
|
-
export type
|
|
63
|
+
export type ExtractArray<T> = MapNeverTo<Extract<T, readonly unknown[]>, unknown[]>;
|
|
61
64
|
|
|
62
|
-
export
|
|
63
|
-
|
|
64
|
-
export interface IsArray {
|
|
65
|
-
(x: unknown): x is unknown[];
|
|
66
|
-
<T>(x: T): x is T extends readonly unknown[] ? T : never;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const isArray: IsArray = Array.isArray;
|
|
65
|
+
export const isArray = Array.isArray as <T>(x: T) => x is ExtractArray<T>;
|
|
70
66
|
|
|
71
67
|
/** Returns `x` if `x` is an array. */
|
|
72
|
-
export const toArray = <T>(x: T): ExtractArray<T> | _ => (isArray(x) ?
|
|
68
|
+
export const toArray = <T>(x: T): ExtractArray<T> | _ => (isArray(x) ? x : _);
|
|
69
|
+
|
|
70
|
+
/** Returns `x` if `x` is an array, otherwise returns `[]` (empty array). */
|
|
71
|
+
export const asArray = <T>(x: T): ExtractArray<T> => (isArray(x) ? x : ([] as ExtractArray<T>));
|
|
73
72
|
|
|
74
73
|
/** Returns `true` if `x` is an array and has at least one element. */
|
|
75
|
-
export const isNonEmptyArray
|
|
74
|
+
export const isNonEmptyArray = <T>(x: T): x is ExtractArray<T> => isArray(x) && x.length > 0;
|
|
76
75
|
|
|
77
76
|
/** Returns `x` if `x` is an array and has at least one element, otherwise returns `undefined`. */
|
|
78
|
-
export const toNonEmptyArray = <T>(x: T): ExtractArray<T> | _ => (isNonEmptyArray(x) ?
|
|
77
|
+
export const toNonEmptyArray = <T>(x: T): ExtractArray<T> | _ => (isNonEmptyArray(x) ? x : _);
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
export type ExtractObject<T> = MapNeverTo<Extract<T, object>, object>;
|
|
80
|
+
|
|
81
|
+
/** Returns `true` if `x` is an object (including array) and not null. */
|
|
82
|
+
export const isObject = <T>(x: T): x is ExtractObject<T> => x !== null && typeof x === "object";
|
|
83
|
+
|
|
84
|
+
/** Returns `x` if `x` is an object (including array). */
|
|
85
|
+
export const toObject = <T>(x: T): ExtractObject<T> | _ => (isObject(x) ? x : _);
|
|
86
|
+
|
|
87
|
+
/** Returns `x` if `x` is an object (including array), otherwise returns `{}` (empty object). */
|
|
88
|
+
export const asObject = <T>(x: T): ExtractObject<T> => (isObject(x) ? x : ({} as ExtractObject<T>));
|
|
82
89
|
|
|
83
90
|
export interface PlainObject {
|
|
84
91
|
[key: PropertyKey]: unknown;
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
export const isObject = (x: unknown): x is object => x !== null && typeof x === "object";
|
|
89
|
-
|
|
90
|
-
/** Returns `x` if `x` is an object (including array), otherwise returns `{}` (empty object). */
|
|
91
|
-
export const asObject = (x: unknown): object => (isObject(x) ? x : {});
|
|
94
|
+
export type ExtractPlainObject<T> = MapNeverTo<Exclude<Extract<T, object>, readonly unknown[]>, PlainObject>;
|
|
92
95
|
|
|
93
96
|
/** Returns `true` if `x` is a plain object (shallow test), not `null` or array. */
|
|
94
|
-
export const isPlainObject = (x:
|
|
97
|
+
export const isPlainObject = <T>(x: T): x is ExtractPlainObject<T> => isObject(x) && !isArray(x);
|
|
95
98
|
|
|
96
99
|
/** Returns `x` if `x` is a plain object. */
|
|
97
|
-
export const toPlainObject = (x:
|
|
100
|
+
export const toPlainObject = <T>(x: T): ExtractPlainObject<T> | _ => (isPlainObject(x) ? x : _);
|
|
98
101
|
|
|
99
102
|
/** Returns `x` if `x` is a plain object, otherwise returns `{}` (empty object). */
|
|
100
|
-
export const asPlainObject = (x:
|
|
103
|
+
export const asPlainObject = <T>(x: T): ExtractPlainObject<T> => (isPlainObject(x) ? x : ({} as ExtractPlainObject<T>));
|
|
101
104
|
|
|
102
105
|
/** Returns `true` if `x` is a plain object and has at least one key. */
|
|
103
|
-
export const isNonEmptyPlainObject = (x:
|
|
106
|
+
export const isNonEmptyPlainObject = <T>(x: T): x is ExtractPlainObject<T> =>
|
|
107
|
+
isPlainObject(x) && Object.keys(x).length > 0;
|
|
104
108
|
|
|
105
109
|
/** Returns `x` if `x` is a plain object and has at least one key. */
|
|
106
|
-
export const toNonEmptyPlainObject = <T
|
|
110
|
+
export const toNonEmptyPlainObject = <T>(x: T): ExtractPlainObject<T> | _ => (isNonEmptyPlainObject(x) ? x : _);
|
|
107
111
|
|
|
108
112
|
/** Returns `true` if `x` is a plain object and has at least one key with non-undefined value. */
|
|
109
|
-
export const isNonEmptyJSONObject = (x:
|
|
113
|
+
export const isNonEmptyJSONObject = <T>(x: T): x is ExtractPlainObject<T> =>
|
|
110
114
|
isPlainObject(x) && Object.values(x).some(isDefined);
|
|
111
115
|
|
|
112
116
|
/** Returns `x` if `x` is a plain object and has at least one key with non-undefined value, otherwise returns `undefined`. */
|
|
113
|
-
export const toNonEmptyJSONObject = <T
|
|
117
|
+
export const toNonEmptyJSONObject = <T>(x: T): ExtractPlainObject<T> | _ => (isNonEmptyJSONObject(x) ? x : _);
|
|
118
|
+
|
|
119
|
+
type ExtractPlainObjectValue<T> = ExtractPlainObject<T>[keyof ExtractPlainObject<T>];
|
|
114
120
|
|
|
115
121
|
/**
|
|
116
122
|
* Creates an object from `x` with keys `k` if `f(x[k])` returns `true`.
|
|
117
123
|
* If `x` is not a plain object, or there's no passed props, returns `undefined`.
|
|
118
124
|
*/
|
|
119
|
-
export const toPlainObjectOf = <T
|
|
125
|
+
export const toPlainObjectOf = <T, U extends ExtractPlainObjectValue<T>>(
|
|
126
|
+
x: T,
|
|
127
|
+
f: (v: ExtractPlainObjectValue<T>) => v is U
|
|
128
|
+
): Record<PropertyKey, U> | _ => {
|
|
120
129
|
if (isPlainObject(x)) {
|
|
121
130
|
let index = -1;
|
|
122
131
|
let props = Object.keys(x);
|
|
123
132
|
let length = props.length;
|
|
124
|
-
let result:
|
|
133
|
+
let result: Record<PropertyKey, U> | _;
|
|
125
134
|
|
|
126
135
|
while (++index < length) {
|
|
127
|
-
let key = props[index];
|
|
136
|
+
let key = props[index] as keyof typeof x;
|
|
128
137
|
let value = x[key];
|
|
129
138
|
if (f(value)) {
|
|
130
139
|
(result ??= {})[key] = value;
|
|
@@ -136,7 +145,7 @@ export const toPlainObjectOf = <T>(x: unknown, f: (v: unknown) => v is T): { [ke
|
|
|
136
145
|
};
|
|
137
146
|
|
|
138
147
|
/** Filter props from object `x` whose values are `true`. */
|
|
139
|
-
export const toPlainObjectOfTrue = (x: unknown):
|
|
148
|
+
export const toPlainObjectOfTrue = (x: unknown): Record<PropertyKey, true> | _ => toPlainObjectOf(x, isTrue);
|
|
140
149
|
|
|
141
150
|
/**
|
|
142
151
|
* Returns `x` if `x` is string, otherwise returns `''` (empty string) if
|