@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 CHANGED
@@ -6,7 +6,14 @@
6
6
  [![Coverage Status](https://wopjs.github.io/cast/coverage-badges/@wopjs/cast.svg)](https://wopjs.github.io/cast/coverage/)
7
7
  [![minified-size](https://img.shields.io/bundlephobia/minzip/@wopjs/cast)](https://bundlephobia.com/package/@wopjs/cast)
8
8
 
9
- Filter types from unknown.
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
- ## Usage
24
+ ## API Pattern
18
25
 
19
- ```js
20
- import * as c from "@wopjs/cast";
21
- import { Option } from "@wopjs/tsur";
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
- const dataParser = {
24
- width: c.toNumber,
25
- position: a => Option.from(a, a => a && c.isNumber(a.x) && c.isNumber(a.y)),
26
- metadata: c.toNonEmptyPlainObject,
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
- function parseData(data) {
30
- const d = c.asObject(data);
31
- return Object.fromEntries(Object.keys(dataParser).map(k => [k, Option.unwrapOr(dataParser[k](d[k]))]));
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
- interface IsFalsy {
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: 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 NormalizeArrayType<T> = T extends readonly unknown[] ? T : unknown[];
40
- type ExtractArray<T> = NormalizeArrayType<Extract<T, readonly unknown[]>>;
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: IsArray;
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
- /** Returns `x` if `x` is an array, otherwise returns `[]` (empty array). */
53
- declare const asArray: <T>(x: T) => ExtractArray<T>;
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
- /** Returns `true` if `x` is an object (including array) and not null. */
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: unknown) => x is PlainObject;
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: unknown) => PlainObject | _;
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: unknown) => PlainObject;
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: unknown) => x is PlainObject;
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 extends PlainObject>(x: T) => 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: unknown) => x is PlainObject;
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 extends PlainObject>(x: T) => 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>(x: unknown, f: (v: unknown) => v is 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 Falsy, type IsArray, type IsFalsy, type NormalizeArrayType, 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, toNonEmptyArray, toNonEmptyJSONObject, toNonEmptyPlainObject, toNonEmptyString, toNumber, toPlainObject, toPlainObjectOf, toPlainObjectOfTrue, toString, toTrue, toTruthy };
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
- interface IsFalsy {
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: 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 NormalizeArrayType<T> = T extends readonly unknown[] ? T : unknown[];
40
- type ExtractArray<T> = NormalizeArrayType<Extract<T, readonly unknown[]>>;
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: IsArray;
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
- /** Returns `x` if `x` is an array, otherwise returns `[]` (empty array). */
53
- declare const asArray: <T>(x: T) => ExtractArray<T>;
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
- /** Returns `true` if `x` is an object (including array) and not null. */
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: unknown) => x is PlainObject;
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: unknown) => PlainObject | _;
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: unknown) => PlainObject;
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: unknown) => x is PlainObject;
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 extends PlainObject>(x: T) => 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: unknown) => x is PlainObject;
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 extends PlainObject>(x: T) => 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>(x: unknown, f: (v: unknown) => v is 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 Falsy, type IsArray, type IsFalsy, type NormalizeArrayType, 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, toNonEmptyArray, toNonEmptyJSONObject, toNonEmptyPlainObject, toNonEmptyString, toNumber, toPlainObject, toPlainObjectOf, toPlainObjectOfTrue, toString, toTrue, toTruthy };
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":"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","file":"index.js"}
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
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/is-to-as.ts","../src/returns.ts"],"names":[],"mappings":"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","file":"index.mjs"}
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.7",
4
- "description": "Filter types from unknown",
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
- "coerce"
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
  {
@@ -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[] | undefined
565
+ // Type narrowing - unknown input returns unknown[]
470
566
  const arr = castType<unknown>(["a", "b"]);
471
- const result: unknown[] | undefined = toNonEmptyArray(arr);
472
- expect(result).toEqual(["a", "b"]);
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: unknown[] | undefined = toNonEmptyArray(arr);
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 interface IsFalsy {
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: IsFalsy = (x: unknown): x is Falsy => !x;
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 NormalizeArrayType<T> = T extends readonly unknown[] ? T : unknown[];
63
+ export type ExtractArray<T> = MapNeverTo<Extract<T, readonly unknown[]>, unknown[]>;
61
64
 
62
- export type ExtractArray<T> = NormalizeArrayType<Extract<T, readonly unknown[]>>;
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) ? (x as ExtractArray<T>) : _);
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: IsArray = (x: unknown): x is unknown[] => isArray(x) && x.length > 0;
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) ? (x as ExtractArray<T>) : _);
77
+ export const toNonEmptyArray = <T>(x: T): ExtractArray<T> | _ => (isNonEmptyArray(x) ? x : _);
79
78
 
80
- /** Returns `x` if `x` is an array, otherwise returns `[]` (empty array). */
81
- export const asArray = <T>(x: T): ExtractArray<T> => (isArray(x) ? (x as ExtractArray<T>) : ([] as ExtractArray<T>));
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
- /** Returns `true` if `x` is an object (including array) and not null. */
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: unknown): x is PlainObject => isObject(x) && !isArray(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: unknown): PlainObject | _ => (isPlainObject(x) ? 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: unknown): PlainObject => (isPlainObject(x) ? 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: unknown): x is PlainObject => isPlainObject(x) && Object.keys(x).length > 0;
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 extends PlainObject>(x: T): T | _ => (isNonEmptyPlainObject(x) ? x : _);
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: unknown): x is PlainObject =>
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 extends PlainObject>(x: T): T | _ => (isNonEmptyJSONObject(x) ? x : _);
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>(x: unknown, f: (v: unknown) => v is T): { [key: PropertyKey]: 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: { [key: PropertyKey]: T } | _;
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): { [key: PropertyKey]: true } | _ => toPlainObjectOf(x, isTrue);
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