deep-guards 1.0.1 → 1.0.3
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 +79 -6
- package/dist/compound.d.ts +7 -1
- package/dist/compound.js +7 -1
- package/dist/compound.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/macros.d.ts +4 -0
- package/dist/macros.js +4 -0
- package/dist/macros.js.map +1 -0
- package/dist/primitives.d.ts +1 -1
- package/dist/structures.d.ts +3 -2
- package/dist/structures.js +16 -8
- package/dist/structures.js.map +1 -1
- package/package.json +5 -5
- package/src/compound.ts +99 -81
- package/src/errors.ts +17 -17
- package/src/index.ts +6 -5
- package/src/macros.ts +11 -0
- package/src/primitives.ts +23 -23
- package/src/structures.ts +105 -83
- package/tests/compound.test.ts +152 -136
- package/tests/macros.test.ts +15 -0
- package/tests/primitives.test.ts +91 -91
- package/tests/structures.test.ts +128 -110
package/README.md
CHANGED
|
@@ -52,15 +52,19 @@ if (vehicleGuard(value)) {
|
|
|
52
52
|
4. [isNot](#isnot)
|
|
53
53
|
5. [isOneOf](#isoneof)
|
|
54
54
|
6. [isUnionOf](#isunionof)
|
|
55
|
-
7. [
|
|
55
|
+
7. [isIntersectionOf](#isintersectionof)
|
|
56
|
+
8. [isExact](#isexact)
|
|
56
57
|
3. [Structures](#structures)
|
|
57
58
|
1. [isAnyArray](#isanyarray)
|
|
58
59
|
2. [isAnyRecord](#isanyrecord)
|
|
59
60
|
3. [isArrayOf](#isarrayof)
|
|
60
|
-
4. [
|
|
61
|
-
5. [
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
4. [isTupleOf](#istupleof)
|
|
62
|
+
5. [isRecordOf](#isrecordof)
|
|
63
|
+
6. [isObjectOf](#isobjectof)
|
|
64
|
+
4. [Macros](#macros)
|
|
65
|
+
1. [isDiscriminatedObjectOf](#isdiscriminatedobjectof)
|
|
66
|
+
5. [guardOrThrow](#guardorthrow)
|
|
67
|
+
6. [TypeFromGuard](#typefromguard)
|
|
64
68
|
|
|
65
69
|
## Terminology
|
|
66
70
|
|
|
@@ -123,7 +127,11 @@ It's very useful for enumerations, where you only have a few specific values, e.
|
|
|
123
127
|
|
|
124
128
|
### isUnionOf
|
|
125
129
|
|
|
126
|
-
Higher order guard. This takes in any amount of guards as arguments, and then produces a guard which does a union over all the incoming guards.
|
|
130
|
+
Higher order guard. This takes in any amount of guards as arguments, and then produces a guard which does a union over all the incoming guards. This means that if _any_ one of the guards passes for the incoming value, then this will pass.
|
|
131
|
+
|
|
132
|
+
### isIntersectionOf
|
|
133
|
+
|
|
134
|
+
Higher order guard. This takes in any amount of guards as arguments, and then produces a guard which does an intersection over all the incoming guards. This means that if _every_ one of the guards passes for the incoming value, then this will pass.
|
|
127
135
|
|
|
128
136
|
### isExact
|
|
129
137
|
|
|
@@ -153,6 +161,21 @@ Higher order guard. This will pass if the incoming value is an array which conta
|
|
|
153
161
|
|
|
154
162
|
NOTE: This passes for empty arrays
|
|
155
163
|
|
|
164
|
+
### isTupleOf
|
|
165
|
+
|
|
166
|
+
Higher order guard. This takes in any number of guards, and then checks that the incoming value is an array of the same size, with the guards guarding the items in the same order as they appear.
|
|
167
|
+
|
|
168
|
+
For example:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
const myTupleGuard = isTupleOf(isNumber, isString, isBoolean);
|
|
172
|
+
const value: unknown = [1, "foo", true];
|
|
173
|
+
|
|
174
|
+
if (myTupleGuard(value)) {
|
|
175
|
+
// value passes
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
156
179
|
### isRecordOf
|
|
157
180
|
|
|
158
181
|
Higher order guard. It has two guard parameters, where the first is the key guard, and then the second is a value guard which is optional. If you don't pass in a value guard, the returned guard function has `unknown`s as the value type.
|
|
@@ -168,6 +191,56 @@ As seen in the example at the start of this readme, you can do all sorts of comp
|
|
|
168
191
|
NOTE: This throws an error if you give it an empty object.\
|
|
169
192
|
It will also accept an object which contains keys which are not specified.
|
|
170
193
|
|
|
194
|
+
## Macros
|
|
195
|
+
|
|
196
|
+
These are common use cases for guarding setups, where they are made entirely out of the above guard suite.
|
|
197
|
+
|
|
198
|
+
### isDiscriminatedObjectOf
|
|
199
|
+
|
|
200
|
+
This takes in a string literal `type`, and an `isObjectOf` guard. This then combines the two, where the returned guard has the signature: `Guard<{ type: T } & O>`.
|
|
201
|
+
This is good for use cases where you don't have a discriminator on an individual type, but then do have it on the union type. For example:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
interface Car {
|
|
205
|
+
wheels: 4;
|
|
206
|
+
owner: string;
|
|
207
|
+
passengers: {
|
|
208
|
+
name: string;
|
|
209
|
+
}[];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface Bike {
|
|
213
|
+
wheels: 2;
|
|
214
|
+
owner: string;
|
|
215
|
+
storage?: string[];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
type Vehicle = ({ type: "car" } & Car) | ({ type: "bike" } & Bike);
|
|
219
|
+
|
|
220
|
+
// Can then be represented like so in guards:
|
|
221
|
+
|
|
222
|
+
const carGuard = isObjectOf({
|
|
223
|
+
wheels: isExact(4),
|
|
224
|
+
owner: isString,
|
|
225
|
+
passengers: isArrayOf(
|
|
226
|
+
isObjectOf({
|
|
227
|
+
name: isString,
|
|
228
|
+
})
|
|
229
|
+
),
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const bikeGuard = isObjectOf({
|
|
233
|
+
wheels: isExact(2),
|
|
234
|
+
owner: isString,
|
|
235
|
+
storage: isOptional(isArrayOf(isString)),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const vehicleGuard = isUnionOf(
|
|
239
|
+
isDiscriminatedObjectOf("car", carGuard),
|
|
240
|
+
isDiscriminatedObjectOf("bike", bikeGuard)
|
|
241
|
+
);
|
|
242
|
+
```
|
|
243
|
+
|
|
171
244
|
## guardOrThrow
|
|
172
245
|
|
|
173
246
|
This package also includes a `guardOrThrow` method which when given an incoming value, a guard, and an optional hint message, will return a narrowed version of the value, or throw a `GuardError` containing that hint message.
|
package/dist/compound.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { Guard, GuardSchemaOf } from "./types
|
|
1
|
+
import { Guard, GuardSchemaOf } from "./types";
|
|
2
2
|
export declare function isOptional<T>(guard: Guard<T>): Guard<T | undefined>;
|
|
3
3
|
export declare function isNullable<T>(guard: Guard<T>): Guard<T | null | undefined>;
|
|
4
4
|
export declare function isNonNullable<T>(value: T | null | undefined): value is T;
|
|
5
5
|
export declare function isNot<const N>(guard: Guard<N>): <const T>(value: T | N) => value is T;
|
|
6
6
|
export declare function isOneOf<const T extends (string | number | boolean | symbol | null | undefined)[]>(...values: T): Guard<(typeof values)[number]>;
|
|
7
7
|
export declare function isUnionOf<T extends readonly unknown[]>(...guards: GuardSchemaOf<T>): Guard<T[number]>;
|
|
8
|
+
type ArrayToIntersection<A extends readonly unknown[]> = A extends [
|
|
9
|
+
infer T,
|
|
10
|
+
...infer R
|
|
11
|
+
] ? T & ArrayToIntersection<R> : unknown;
|
|
12
|
+
export declare function isIntersectionOf<T extends readonly unknown[]>(...guards: GuardSchemaOf<T>): Guard<ArrayToIntersection<T>>;
|
|
8
13
|
export declare function isExact<const T>(expected: T, deep?: boolean): Guard<T>;
|
|
14
|
+
export {};
|
package/dist/compound.js
CHANGED
|
@@ -2,7 +2,7 @@ export function isOptional(guard) {
|
|
|
2
2
|
if (typeof guard !== "function") {
|
|
3
3
|
throw new TypeError(`isOptional expects a guard parameter. Got instead: ${guard}`);
|
|
4
4
|
}
|
|
5
|
-
return (
|
|
5
|
+
return (value) => value === undefined || guard(value);
|
|
6
6
|
}
|
|
7
7
|
export function isNullable(guard) {
|
|
8
8
|
if (typeof guard !== "function") {
|
|
@@ -29,6 +29,12 @@ export function isUnionOf(...guards) {
|
|
|
29
29
|
}
|
|
30
30
|
return (value) => guards.some((guard) => guard(value));
|
|
31
31
|
}
|
|
32
|
+
export function isIntersectionOf(...guards) {
|
|
33
|
+
if (guards.every((guard) => typeof guard !== "function")) {
|
|
34
|
+
throw new TypeError(`isIntersectionOf expects N guard parameters. Got instead: ${guards}`);
|
|
35
|
+
}
|
|
36
|
+
return (value) => guards.every((guard) => guard(value));
|
|
37
|
+
}
|
|
32
38
|
function isEqual(a, b) {
|
|
33
39
|
return (a === b ||
|
|
34
40
|
(a != null &&
|
package/dist/compound.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compound.js","sourceRoot":"src/","sources":["compound.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAI,KAAe;IAC3C,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CACjB,sDAAsD,KAAK,EAAE,CAC9D,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"compound.js","sourceRoot":"src/","sources":["compound.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export * from "./compound
|
|
2
|
-
export * from "./errors
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
1
|
+
export * from "./compound";
|
|
2
|
+
export * from "./errors";
|
|
3
|
+
export * from "./macros";
|
|
4
|
+
export * from "./primitives";
|
|
5
|
+
export * from "./structures";
|
|
6
|
+
export * from "./types";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export * from "./compound
|
|
2
|
-
export * from "./errors
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
1
|
+
export * from "./compound";
|
|
2
|
+
export * from "./errors";
|
|
3
|
+
export * from "./macros";
|
|
4
|
+
export * from "./primitives";
|
|
5
|
+
export * from "./structures";
|
|
6
|
+
export * from "./types";
|
|
6
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"src/","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"src/","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC"}
|
package/dist/macros.d.ts
ADDED
package/dist/macros.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macros.js","sourceRoot":"src/","sources":["macros.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,IAAO,EACP,KAAe,EACS,EAAE,CAC1B,gBAAgB,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,CAE1D,CAAC"}
|
package/dist/primitives.d.ts
CHANGED
package/dist/structures.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Guard, GuardSchemaOf } from "./types
|
|
1
|
+
import { Guard, GuardSchemaOf } from "./types";
|
|
2
2
|
type ObjectKey = string | number | symbol;
|
|
3
3
|
export declare const isAnyArray: Guard<unknown[]>;
|
|
4
4
|
export declare const isAnyRecord: Guard<Record<ObjectKey, unknown>>;
|
|
5
5
|
export declare function isArrayOf<T>(guard: Guard<T>): Guard<T[]>;
|
|
6
|
+
export declare function isTupleOf<T extends readonly unknown[]>(...tupleGuards: GuardSchemaOf<T>): Guard<T>;
|
|
6
7
|
export declare function isRecordOf<K extends ObjectKey>(keyGuard: Guard<K>): Guard<Record<K, unknown>>;
|
|
7
8
|
export declare function isRecordOf<K extends ObjectKey, V>(keyGuard: Guard<K>, valueGuard: Guard<V>): Guard<Record<K, V>>;
|
|
8
|
-
export declare function isObjectOf<O extends object>(schema: GuardSchemaOf<O>): O extends unknown[] ? never : Guard<O>;
|
|
9
|
+
export declare function isObjectOf<O extends object>(schema: GuardSchemaOf<O>): O extends unknown[] ? never : {} extends O ? never : Guard<O>;
|
|
9
10
|
export {};
|
package/dist/structures.js
CHANGED
|
@@ -9,6 +9,14 @@ export function isArrayOf(guard) {
|
|
|
9
9
|
}
|
|
10
10
|
return (value) => Array.isArray(value) && value.every(guard);
|
|
11
11
|
}
|
|
12
|
+
export function isTupleOf(...tupleGuards) {
|
|
13
|
+
if (tupleGuards.some((guard) => typeof guard !== "function")) {
|
|
14
|
+
throw new TypeError(`isTupleOf expects guard parameters. Got instead: ${JSON.stringify(tupleGuards)}`);
|
|
15
|
+
}
|
|
16
|
+
return (value) => Array.isArray(value) &&
|
|
17
|
+
value.length === tupleGuards.length &&
|
|
18
|
+
tupleGuards.every((guard, i) => guard(value[i]));
|
|
19
|
+
}
|
|
12
20
|
export function isRecordOf(keyGuard, valueGuard) {
|
|
13
21
|
if (typeof keyGuard !== "function") {
|
|
14
22
|
throw new TypeError(`isRecordOf keyGuard expects a guard parameter. Got instead: ${keyGuard}`);
|
|
@@ -22,16 +30,16 @@ export function isRecordOf(keyGuard, valueGuard) {
|
|
|
22
30
|
objectKeys(value).every((key) => keyGuard(key) && (valueGuard?.(value[key]) ?? true));
|
|
23
31
|
}
|
|
24
32
|
export function isObjectOf(schema) {
|
|
33
|
+
if (schema == null || typeof schema !== "object") {
|
|
34
|
+
throw new TypeError(`isObjectOf expects a guard schema object. Got instead: ${schema}`);
|
|
35
|
+
}
|
|
25
36
|
const schemaKeys = objectKeys(schema);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
throw new
|
|
37
|
+
if (Array.isArray(schema) ||
|
|
38
|
+
schemaKeys.some((key) => typeof schema[key] !== "function")) {
|
|
39
|
+
throw new TypeError(`isObjectOf expects a guard schema object. Got instead ${JSON.stringify(schema)}`);
|
|
29
40
|
}
|
|
30
|
-
else if (
|
|
31
|
-
|
|
32
|
-
Array.isArray(schemaUnknown) ||
|
|
33
|
-
schemaKeys.some((key) => typeof schemaUnknown[key] !== "function")) {
|
|
34
|
-
throw new TypeError(`isObjectOf expects a guard schema. Got instead: ${schemaUnknown}`);
|
|
41
|
+
else if (schemaKeys.length === 0) {
|
|
42
|
+
throw new Error("isObjectOf received an empty schema");
|
|
35
43
|
}
|
|
36
44
|
return ((value) => value != null &&
|
|
37
45
|
typeof value === "object" &&
|
package/dist/structures.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structures.js","sourceRoot":"src/","sources":["structures.ts"],"names":[],"mappings":"AAIA,SAAS,UAAU,CAAsB,GAAuB;IAC9D,OAAQ,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAS,CAAC,MAAM,CACpD,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAQ,CACzC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAE5E,MAAM,CAAC,MAAM,WAAW,GAAsC,CAC5D,KAAK,EACgC,EAAE,CACvC,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEtE,MAAM,UAAU,SAAS,CAAI,KAAe;IAC1C,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CACjB,qDAAqD,KAAK,EAAE,CAC7D,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,KAAK,EAAgB,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AASD,MAAM,UAAU,UAAU,CACxB,QAAkB,EAClB,UAAqB;IAErB,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,SAAS,CACjB,+DAA+D,QAAQ,EAAE,CAC1E,CAAC;IACJ,CAAC;SAAM,IAAI,UAAU,IAAI,IAAI,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;QAClE,MAAM,IAAI,SAAS,CACjB,2EAA2E,UAAU,EAAE,CACxF,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,KAAK,EAAyB,EAAE,CACtC,KAAK,IAAI,IAAI;QACb,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,CACrB,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAC7D,CAAC;AACN,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,MAAwB;IAExB,
|
|
1
|
+
{"version":3,"file":"structures.js","sourceRoot":"src/","sources":["structures.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "module",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
10
|
"homepage": "https://github.com/eniallator/Deep-Guards",
|
|
11
|
-
"version": "1.0.
|
|
11
|
+
"version": "1.0.3",
|
|
12
12
|
"scripts": {
|
|
13
13
|
"test": "jest",
|
|
14
14
|
"build": "tsc",
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"@types/eslint": "^9.6.1",
|
|
29
29
|
"@types/eslint__js": "^8.42.3",
|
|
30
30
|
"@types/jest": "^29.5.14",
|
|
31
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
32
|
-
"@typescript-eslint/parser": "^8.
|
|
31
|
+
"@typescript-eslint/eslint-plugin": "^8.16.0",
|
|
32
|
+
"@typescript-eslint/parser": "^8.16.0",
|
|
33
33
|
"babel-jest": "^29.7.0",
|
|
34
34
|
"eslint": "^9.15.0",
|
|
35
35
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
36
36
|
"eslint-plugin-import": "^2.31.0",
|
|
37
37
|
"eslint-plugin-jest": "^28.9.0",
|
|
38
38
|
"jest": "^29.7.0",
|
|
39
|
-
"typescript": "^5.
|
|
40
|
-
"typescript-eslint": "^8.
|
|
39
|
+
"typescript": "^5.7.2",
|
|
40
|
+
"typescript-eslint": "^8.16.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/src/compound.ts
CHANGED
|
@@ -1,81 +1,99 @@
|
|
|
1
|
-
import { Guard, GuardSchemaOf } from "./types
|
|
2
|
-
|
|
3
|
-
export function isOptional<T>(guard: Guard<T>): Guard<T | undefined> {
|
|
4
|
-
if (typeof guard !== "function") {
|
|
5
|
-
throw new TypeError(
|
|
6
|
-
`isOptional expects a guard parameter. Got instead: ${guard}`
|
|
7
|
-
);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
|
|
81
|
-
|
|
1
|
+
import { Guard, GuardSchemaOf } from "./types";
|
|
2
|
+
|
|
3
|
+
export function isOptional<T>(guard: Guard<T>): Guard<T | undefined> {
|
|
4
|
+
if (typeof guard !== "function") {
|
|
5
|
+
throw new TypeError(
|
|
6
|
+
`isOptional expects a guard parameter. Got instead: ${guard}`
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return (value): value is T | undefined => value === undefined || guard(value);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isNullable<T>(guard: Guard<T>): Guard<T | null | undefined> {
|
|
14
|
+
if (typeof guard !== "function") {
|
|
15
|
+
throw new TypeError(
|
|
16
|
+
`isNullable expects a guard parameter. Got instead: ${guard}`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (value: unknown): value is T | null | undefined =>
|
|
21
|
+
value == null || guard(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isNonNullable<T>(value: T | null | undefined): value is T {
|
|
25
|
+
return value != null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isNot<const N>(guard: Guard<N>) {
|
|
29
|
+
if (typeof guard !== "function") {
|
|
30
|
+
throw new TypeError(
|
|
31
|
+
`isNot expects a guard parameter. Got instead: ${guard}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return <const T>(value: T | N): value is T => !guard(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function isOneOf<
|
|
39
|
+
const T extends (string | number | boolean | symbol | null | undefined)[]
|
|
40
|
+
>(...values: T): Guard<(typeof values)[number]> {
|
|
41
|
+
const valueSet = new Set(values);
|
|
42
|
+
return (value: unknown): value is T[number] =>
|
|
43
|
+
valueSet.has(value as T[number]);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function isUnionOf<T extends readonly unknown[]>(
|
|
47
|
+
...guards: GuardSchemaOf<T>
|
|
48
|
+
): Guard<T[number]> {
|
|
49
|
+
if (guards.every((guard) => typeof guard !== "function")) {
|
|
50
|
+
throw new TypeError(
|
|
51
|
+
`isUnionOf expects N guard parameters. Got instead: ${guards}`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (value): value is T => guards.some((guard) => guard(value));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type ArrayToIntersection<A extends readonly unknown[]> = A extends [
|
|
59
|
+
infer T,
|
|
60
|
+
...infer R
|
|
61
|
+
]
|
|
62
|
+
? T & ArrayToIntersection<R>
|
|
63
|
+
: unknown;
|
|
64
|
+
|
|
65
|
+
export function isIntersectionOf<T extends readonly unknown[]>(
|
|
66
|
+
...guards: GuardSchemaOf<T>
|
|
67
|
+
): Guard<ArrayToIntersection<T>> {
|
|
68
|
+
if (guards.every((guard) => typeof guard !== "function")) {
|
|
69
|
+
throw new TypeError(
|
|
70
|
+
`isIntersectionOf expects N guard parameters. Got instead: ${guards}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (value): value is ArrayToIntersection<T> =>
|
|
75
|
+
guards.every((guard) => guard(value));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isEqual<T>(a: T, b: unknown): b is T {
|
|
79
|
+
return (
|
|
80
|
+
a === b ||
|
|
81
|
+
(a != null &&
|
|
82
|
+
b != null &&
|
|
83
|
+
typeof a === "object" &&
|
|
84
|
+
typeof b === "object" &&
|
|
85
|
+
(Array.isArray(a)
|
|
86
|
+
? Array.isArray(b) &&
|
|
87
|
+
a.length === b.length &&
|
|
88
|
+
a.every((v, i) => isEqual(v, b[i]))
|
|
89
|
+
: Object.keys(a).length === Object.keys(b).length &&
|
|
90
|
+
Object.entries(a).every(
|
|
91
|
+
([k, v]) => k in b && isEqual(v, (b as Record<string, unknown>)[k])
|
|
92
|
+
)))
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function isExact<const T>(expected: T, deep: boolean = true): Guard<T> {
|
|
97
|
+
return (value): value is T =>
|
|
98
|
+
deep ? isEqual(expected, value) : expected === value;
|
|
99
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Guard } from "./types
|
|
2
|
-
|
|
3
|
-
export class GuardError extends Error {
|
|
4
|
-
name = "GuardError";
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function guardOrThrow<T>(
|
|
8
|
-
value: unknown,
|
|
9
|
-
guard: Guard<T>,
|
|
10
|
-
hint?: string
|
|
11
|
-
): T {
|
|
12
|
-
if (guard(value)) {
|
|
13
|
-
return value;
|
|
14
|
-
} else {
|
|
15
|
-
throw new GuardError(hint ?? "Guard error");
|
|
16
|
-
}
|
|
17
|
-
}
|
|
1
|
+
import { Guard } from "./types";
|
|
2
|
+
|
|
3
|
+
export class GuardError extends Error {
|
|
4
|
+
name = "GuardError";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function guardOrThrow<T>(
|
|
8
|
+
value: unknown,
|
|
9
|
+
guard: Guard<T>,
|
|
10
|
+
hint?: string
|
|
11
|
+
): T {
|
|
12
|
+
if (guard(value)) {
|
|
13
|
+
return value;
|
|
14
|
+
} else {
|
|
15
|
+
throw new GuardError(hint ?? "Guard error");
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export * from "./compound
|
|
2
|
-
export * from "./errors
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
1
|
+
export * from "./compound";
|
|
2
|
+
export * from "./errors";
|
|
3
|
+
export * from "./macros";
|
|
4
|
+
export * from "./primitives";
|
|
5
|
+
export * from "./structures";
|
|
6
|
+
export * from "./types";
|
package/src/macros.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isExact, isIntersectionOf } from "./compound";
|
|
2
|
+
import { isObjectOf } from "./structures";
|
|
3
|
+
import { Guard } from "./types";
|
|
4
|
+
|
|
5
|
+
export const isDiscriminatedObjectOf = <T extends string, O extends object>(
|
|
6
|
+
type: T,
|
|
7
|
+
guard: Guard<O>
|
|
8
|
+
): Guard<{ type: T } & O> =>
|
|
9
|
+
isIntersectionOf(isObjectOf({ type: isExact(type) }), guard) satisfies Guard<
|
|
10
|
+
{ type: T } & O
|
|
11
|
+
>;
|
package/src/primitives.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { Guard } from "./types
|
|
2
|
-
|
|
3
|
-
export const isUnknown: Guard<unknown> = (_value): _value is unknown => true;
|
|
4
|
-
|
|
5
|
-
export const isNull: Guard<null> = (value) => value === null;
|
|
6
|
-
|
|
7
|
-
export const isUndefined: Guard<undefined> = (value) => value === undefined;
|
|
8
|
-
|
|
9
|
-
export const isNumber: Guard<number> = (value) => typeof value === "number";
|
|
10
|
-
|
|
11
|
-
export const isInteger: Guard<number> = (value): value is number =>
|
|
12
|
-
Number.isInteger(value);
|
|
13
|
-
|
|
14
|
-
export const isString: Guard<string> = (value) => typeof value === "string";
|
|
15
|
-
|
|
16
|
-
export const isSymbol: Guard<symbol> = (value) => typeof value === "symbol";
|
|
17
|
-
|
|
18
|
-
export const isBoolean: Guard<boolean> = (value) =>
|
|
19
|
-
value === true || value === false;
|
|
20
|
-
|
|
21
|
-
export const isFunction: Guard<(...args: unknown[]) => unknown> = (
|
|
22
|
-
value
|
|
23
|
-
): value is (...args: unknown[]) => unknown => typeof value === "function";
|
|
1
|
+
import { Guard } from "./types";
|
|
2
|
+
|
|
3
|
+
export const isUnknown: Guard<unknown> = (_value): _value is unknown => true;
|
|
4
|
+
|
|
5
|
+
export const isNull: Guard<null> = (value) => value === null;
|
|
6
|
+
|
|
7
|
+
export const isUndefined: Guard<undefined> = (value) => value === undefined;
|
|
8
|
+
|
|
9
|
+
export const isNumber: Guard<number> = (value) => typeof value === "number";
|
|
10
|
+
|
|
11
|
+
export const isInteger: Guard<number> = (value): value is number =>
|
|
12
|
+
Number.isInteger(value);
|
|
13
|
+
|
|
14
|
+
export const isString: Guard<string> = (value) => typeof value === "string";
|
|
15
|
+
|
|
16
|
+
export const isSymbol: Guard<symbol> = (value) => typeof value === "symbol";
|
|
17
|
+
|
|
18
|
+
export const isBoolean: Guard<boolean> = (value) =>
|
|
19
|
+
value === true || value === false;
|
|
20
|
+
|
|
21
|
+
export const isFunction: Guard<(...args: unknown[]) => unknown> = (
|
|
22
|
+
value
|
|
23
|
+
): value is (...args: unknown[]) => unknown => typeof value === "function";
|