effect 3.16.13 → 3.16.14
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/dist/cjs/Predicate.js +516 -200
- package/dist/cjs/Predicate.js.map +1 -1
- package/dist/cjs/Schema.js +2 -2
- package/dist/cjs/Schema.js.map +1 -1
- package/dist/cjs/internal/channel.js +2 -2
- package/dist/cjs/internal/channel.js.map +1 -1
- package/dist/cjs/internal/core-effect.js +1 -0
- package/dist/cjs/internal/core-effect.js.map +1 -1
- package/dist/cjs/internal/dataSource.js +2 -2
- package/dist/cjs/internal/dataSource.js.map +1 -1
- package/dist/cjs/internal/fiberRuntime.js +1 -1
- package/dist/cjs/internal/fiberRuntime.js.map +1 -1
- package/dist/cjs/internal/groupBy.js +2 -2
- package/dist/cjs/internal/groupBy.js.map +1 -1
- package/dist/cjs/internal/sink.js +4 -4
- package/dist/cjs/internal/sink.js.map +1 -1
- package/dist/cjs/internal/stm/stm.js +3 -3
- package/dist/cjs/internal/stm/stm.js.map +1 -1
- package/dist/cjs/internal/stream.js +5 -5
- package/dist/cjs/internal/stream.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Effect.d.ts +1 -1
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/Predicate.d.ts +1190 -375
- package/dist/dts/Predicate.d.ts.map +1 -1
- package/dist/dts/index.d.ts +15 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/core-effect.d.ts.map +1 -1
- package/dist/dts/internal/stm/stm.d.ts.map +1 -1
- package/dist/dts/internal/stream.d.ts.map +1 -1
- package/dist/esm/Predicate.js +516 -200
- package/dist/esm/Predicate.js.map +1 -1
- package/dist/esm/Schema.js +2 -2
- package/dist/esm/Schema.js.map +1 -1
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/channel.js +2 -2
- package/dist/esm/internal/channel.js.map +1 -1
- package/dist/esm/internal/core-effect.js +1 -0
- package/dist/esm/internal/core-effect.js.map +1 -1
- package/dist/esm/internal/dataSource.js +2 -2
- package/dist/esm/internal/dataSource.js.map +1 -1
- package/dist/esm/internal/fiberRuntime.js +1 -1
- package/dist/esm/internal/fiberRuntime.js.map +1 -1
- package/dist/esm/internal/groupBy.js +2 -2
- package/dist/esm/internal/groupBy.js.map +1 -1
- package/dist/esm/internal/sink.js +4 -4
- package/dist/esm/internal/sink.js.map +1 -1
- package/dist/esm/internal/stm/stm.js +3 -3
- package/dist/esm/internal/stm/stm.js.map +1 -1
- package/dist/esm/internal/stream.js +5 -5
- package/dist/esm/internal/stream.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +1 -1
- package/src/Effect.ts +1 -1
- package/src/Predicate.ts +1213 -377
- package/src/Schema.ts +2 -2
- package/src/index.ts +15 -0
- package/src/internal/channel.ts +2 -2
- package/src/internal/core-effect.ts +1 -0
- package/src/internal/dataSource.ts +12 -14
- package/src/internal/fiberRuntime.ts +2 -2
- package/src/internal/groupBy.ts +12 -14
- package/src/internal/sink.ts +13 -15
- package/src/internal/stm/stm.ts +16 -20
- package/src/internal/stream.ts +17 -23
- package/src/internal/version.ts +1 -1
package/dist/esm/Predicate.js
CHANGED
|
@@ -1,21 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* This module provides a collection of functions for working with predicates and refinements.
|
|
3
|
+
*
|
|
4
|
+
* A `Predicate<A>` is a function that takes a value of type `A` and returns a boolean.
|
|
5
|
+
* It is used to check if a value satisfies a certain condition.
|
|
6
|
+
*
|
|
7
|
+
* A `Refinement<A, B>` is a special type of predicate that not only checks a condition
|
|
8
|
+
* but also provides a type guard, allowing TypeScript to narrow the type of the input
|
|
9
|
+
* value from `A` to a more specific type `B` within a conditional block.
|
|
10
|
+
*
|
|
11
|
+
* The module includes:
|
|
12
|
+
* - Basic predicates and refinements for common types (e.g., `isString`, `isNumber`).
|
|
13
|
+
* - Combinators to create new predicates from existing ones (e.g., `and`, `or`, `not`).
|
|
14
|
+
* - Advanced combinators for working with data structures (e.g., `tuple`, `struct`).
|
|
15
|
+
* - Type-level utilities for inspecting predicate and refinement types.
|
|
16
|
+
*
|
|
2
17
|
* @since 2.0.0
|
|
3
18
|
*/
|
|
4
19
|
import { dual, isFunction as isFunction_ } from "./Function.js";
|
|
5
20
|
/**
|
|
6
|
-
*
|
|
21
|
+
* Transforms a `Predicate<A>` into a `Predicate<B>` by applying a function `(b: B) => A`
|
|
22
|
+
* to the input before passing it to the predicate. This is also known as "contramap" or
|
|
23
|
+
* "pre-composition".
|
|
7
24
|
*
|
|
8
25
|
* @example
|
|
9
26
|
* ```ts
|
|
10
|
-
* import * as assert from "node:assert"
|
|
11
27
|
* import { Predicate, Number } from "effect"
|
|
28
|
+
* import * as assert from "node:assert"
|
|
29
|
+
*
|
|
30
|
+
* // A predicate on numbers
|
|
31
|
+
* const isPositive: Predicate.Predicate<number> = Number.greaterThan(0)
|
|
12
32
|
*
|
|
13
|
-
*
|
|
33
|
+
* // A function from `string` to `number`
|
|
34
|
+
* const stringLength = (s: string): number => s.length
|
|
14
35
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* assert.
|
|
36
|
+
* // Create a new predicate on strings by mapping the input
|
|
37
|
+
* const hasPositiveLength = Predicate.mapInput(isPositive, stringLength)
|
|
38
|
+
*
|
|
39
|
+
* assert.strictEqual(hasPositiveLength("hello"), true)
|
|
40
|
+
* assert.strictEqual(hasPositiveLength(""), false)
|
|
19
41
|
* ```
|
|
20
42
|
*
|
|
21
43
|
* @category combinators
|
|
@@ -23,23 +45,24 @@ import { dual, isFunction as isFunction_ } from "./Function.js";
|
|
|
23
45
|
*/
|
|
24
46
|
export const mapInput = /*#__PURE__*/dual(2, (self, f) => b => self(f(b)));
|
|
25
47
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* An `Array` is considered to be a `TupleOf` if its length is exactly `N`.
|
|
48
|
+
* A refinement that checks if a `ReadonlyArray<T>` is a tuple with exactly `N` elements.
|
|
49
|
+
* If the check is successful, the type is narrowed to `TupleOf<N, T>`.
|
|
29
50
|
*
|
|
30
51
|
* @example
|
|
31
52
|
* ```ts
|
|
32
53
|
* import * as assert from "node:assert"
|
|
33
54
|
* import { isTupleOf } from "effect/Predicate"
|
|
34
55
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* assert.
|
|
56
|
+
* const isTupleOf3 = isTupleOf(3)
|
|
57
|
+
*
|
|
58
|
+
* assert.strictEqual(isTupleOf3([1, 2, 3]), true);
|
|
59
|
+
* assert.strictEqual(isTupleOf3([1, 2]), false);
|
|
38
60
|
*
|
|
39
61
|
* const arr: number[] = [1, 2, 3];
|
|
40
62
|
* if (isTupleOf(arr, 3)) {
|
|
41
|
-
*
|
|
42
|
-
*
|
|
63
|
+
* // The type of arr is now [number, number, number]
|
|
64
|
+
* const [a, b, c] = arr;
|
|
65
|
+
* assert.deepStrictEqual([a, b, c], [1, 2, 3])
|
|
43
66
|
* }
|
|
44
67
|
* ```
|
|
45
68
|
*
|
|
@@ -48,23 +71,25 @@ export const mapInput = /*#__PURE__*/dual(2, (self, f) => b => self(f(b)));
|
|
|
48
71
|
*/
|
|
49
72
|
export const isTupleOf = /*#__PURE__*/dual(2, (self, n) => self.length === n);
|
|
50
73
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* An `Array` is considered to be a `TupleOfAtLeast` if its length is at least `N`.
|
|
74
|
+
* A refinement that checks if a `ReadonlyArray<T>` is a tuple with at least `N` elements.
|
|
75
|
+
* If the check is successful, the type is narrowed to `TupleOfAtLeast<N, T>`.
|
|
54
76
|
*
|
|
55
77
|
* @example
|
|
56
78
|
* ```ts
|
|
57
79
|
* import * as assert from "node:assert"
|
|
58
80
|
* import { isTupleOfAtLeast } from "effect/Predicate"
|
|
59
81
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* assert.
|
|
82
|
+
* const isTupleOfAtLeast3 = isTupleOfAtLeast(3)
|
|
83
|
+
*
|
|
84
|
+
* assert.strictEqual(isTupleOfAtLeast3([1, 2, 3]), true);
|
|
85
|
+
* assert.strictEqual(isTupleOfAtLeast3([1, 2, 3, 4]), true);
|
|
86
|
+
* assert.strictEqual(isTupleOfAtLeast3([1, 2]), false);
|
|
63
87
|
*
|
|
64
88
|
* const arr: number[] = [1, 2, 3, 4];
|
|
65
89
|
* if (isTupleOfAtLeast(arr, 3)) {
|
|
66
|
-
*
|
|
67
|
-
*
|
|
90
|
+
* // The type of arr is now [number, number, number, ...number[]]
|
|
91
|
+
* const [a, b, c] = arr;
|
|
92
|
+
* assert.deepStrictEqual([a, b, c], [1, 2, 3])
|
|
68
93
|
* }
|
|
69
94
|
* ```
|
|
70
95
|
*
|
|
@@ -73,16 +98,22 @@ export const isTupleOf = /*#__PURE__*/dual(2, (self, n) => self.length === n);
|
|
|
73
98
|
*/
|
|
74
99
|
export const isTupleOfAtLeast = /*#__PURE__*/dual(2, (self, n) => self.length >= n);
|
|
75
100
|
/**
|
|
76
|
-
*
|
|
101
|
+
* A predicate that checks if a value is "truthy" in JavaScript.
|
|
102
|
+
* Fails for `false`, `0`, `-0`, `0n`, `""`, `null`, `undefined`, and `NaN`.
|
|
77
103
|
*
|
|
78
104
|
* @example
|
|
79
105
|
* ```ts
|
|
80
106
|
* import * as assert from "node:assert"
|
|
81
107
|
* import { isTruthy } from "effect/Predicate"
|
|
82
108
|
*
|
|
83
|
-
* assert.
|
|
84
|
-
* assert.
|
|
85
|
-
* assert.
|
|
109
|
+
* assert.strictEqual(isTruthy(1), true)
|
|
110
|
+
* assert.strictEqual(isTruthy("hello"), true)
|
|
111
|
+
* assert.strictEqual(isTruthy({}), true)
|
|
112
|
+
*
|
|
113
|
+
* assert.strictEqual(isTruthy(0), false)
|
|
114
|
+
* assert.strictEqual(isTruthy(""), false)
|
|
115
|
+
* assert.strictEqual(isTruthy(null), false)
|
|
116
|
+
* assert.strictEqual(isTruthy(undefined), false)
|
|
86
117
|
* ```
|
|
87
118
|
*
|
|
88
119
|
* @category guards
|
|
@@ -90,18 +121,18 @@ export const isTupleOfAtLeast = /*#__PURE__*/dual(2, (self, n) => self.length >=
|
|
|
90
121
|
*/
|
|
91
122
|
export const isTruthy = input => !!input;
|
|
92
123
|
/**
|
|
93
|
-
*
|
|
124
|
+
* A refinement that checks if a value is a `Set`.
|
|
94
125
|
*
|
|
95
126
|
* @example
|
|
96
127
|
* ```ts
|
|
97
128
|
* import * as assert from "node:assert"
|
|
98
129
|
* import { isSet } from "effect/Predicate"
|
|
99
130
|
*
|
|
100
|
-
* assert.
|
|
101
|
-
* assert.
|
|
102
|
-
*
|
|
103
|
-
* assert.
|
|
104
|
-
* assert.
|
|
131
|
+
* assert.strictEqual(isSet(new Set([1, 2])), true)
|
|
132
|
+
* assert.strictEqual(isSet(new Set()), true)
|
|
133
|
+
*
|
|
134
|
+
* assert.strictEqual(isSet({}), false)
|
|
135
|
+
* assert.strictEqual(isSet([1, 2]), false)
|
|
105
136
|
* ```
|
|
106
137
|
*
|
|
107
138
|
* @category guards
|
|
@@ -109,17 +140,17 @@ export const isTruthy = input => !!input;
|
|
|
109
140
|
*/
|
|
110
141
|
export const isSet = input => input instanceof Set;
|
|
111
142
|
/**
|
|
112
|
-
*
|
|
143
|
+
* A refinement that checks if a value is a `Map`.
|
|
113
144
|
*
|
|
114
145
|
* @example
|
|
115
146
|
* ```ts
|
|
116
147
|
* import * as assert from "node:assert"
|
|
117
148
|
* import { isMap } from "effect/Predicate"
|
|
118
149
|
*
|
|
119
|
-
* assert.
|
|
120
|
-
*
|
|
121
|
-
* assert.
|
|
122
|
-
* assert.
|
|
150
|
+
* assert.strictEqual(isMap(new Map()), true)
|
|
151
|
+
*
|
|
152
|
+
* assert.strictEqual(isMap({}), false)
|
|
153
|
+
* assert.strictEqual(isMap(new Set()), false)
|
|
123
154
|
* ```
|
|
124
155
|
*
|
|
125
156
|
* @category guards
|
|
@@ -127,16 +158,18 @@ export const isSet = input => input instanceof Set;
|
|
|
127
158
|
*/
|
|
128
159
|
export const isMap = input => input instanceof Map;
|
|
129
160
|
/**
|
|
130
|
-
*
|
|
161
|
+
* A refinement that checks if a value is a `string`.
|
|
131
162
|
*
|
|
132
163
|
* @example
|
|
133
164
|
* ```ts
|
|
134
165
|
* import * as assert from "node:assert"
|
|
135
166
|
* import { isString } from "effect/Predicate"
|
|
136
167
|
*
|
|
137
|
-
* assert.
|
|
168
|
+
* assert.strictEqual(isString("hello"), true)
|
|
169
|
+
* assert.strictEqual(isString(""), true)
|
|
138
170
|
*
|
|
139
|
-
* assert.
|
|
171
|
+
* assert.strictEqual(isString(123), false)
|
|
172
|
+
* assert.strictEqual(isString(null), false)
|
|
140
173
|
* ```
|
|
141
174
|
*
|
|
142
175
|
* @category guards
|
|
@@ -144,16 +177,20 @@ export const isMap = input => input instanceof Map;
|
|
|
144
177
|
*/
|
|
145
178
|
export const isString = input => typeof input === "string";
|
|
146
179
|
/**
|
|
147
|
-
*
|
|
180
|
+
* A refinement that checks if a value is a `number`. Note that this
|
|
181
|
+
* check returns `false` for `NaN`.
|
|
148
182
|
*
|
|
149
183
|
* @example
|
|
150
184
|
* ```ts
|
|
151
185
|
* import * as assert from "node:assert"
|
|
152
186
|
* import { isNumber } from "effect/Predicate"
|
|
153
187
|
*
|
|
154
|
-
* assert.
|
|
188
|
+
* assert.strictEqual(isNumber(123), true)
|
|
189
|
+
* assert.strictEqual(isNumber(0), true)
|
|
190
|
+
* assert.strictEqual(isNumber(-1.5), true)
|
|
155
191
|
*
|
|
156
|
-
* assert.
|
|
192
|
+
* assert.strictEqual(isNumber("123"), false)
|
|
193
|
+
* assert.strictEqual(isNumber(NaN), false) // Special case: NaN is a number type but returns false
|
|
157
194
|
* ```
|
|
158
195
|
*
|
|
159
196
|
* @category guards
|
|
@@ -161,16 +198,18 @@ export const isString = input => typeof input === "string";
|
|
|
161
198
|
*/
|
|
162
199
|
export const isNumber = input => typeof input === "number";
|
|
163
200
|
/**
|
|
164
|
-
*
|
|
201
|
+
* A refinement that checks if a value is a `boolean`.
|
|
165
202
|
*
|
|
166
203
|
* @example
|
|
167
204
|
* ```ts
|
|
168
205
|
* import * as assert from "node:assert"
|
|
169
206
|
* import { isBoolean } from "effect/Predicate"
|
|
170
207
|
*
|
|
171
|
-
* assert.
|
|
208
|
+
* assert.strictEqual(isBoolean(true), true)
|
|
209
|
+
* assert.strictEqual(isBoolean(false), true)
|
|
172
210
|
*
|
|
173
|
-
* assert.
|
|
211
|
+
* assert.strictEqual(isBoolean("true"), false)
|
|
212
|
+
* assert.strictEqual(isBoolean(0), false)
|
|
174
213
|
* ```
|
|
175
214
|
*
|
|
176
215
|
* @category guards
|
|
@@ -178,16 +217,17 @@ export const isNumber = input => typeof input === "number";
|
|
|
178
217
|
*/
|
|
179
218
|
export const isBoolean = input => typeof input === "boolean";
|
|
180
219
|
/**
|
|
181
|
-
*
|
|
220
|
+
* A refinement that checks if a value is a `bigint`.
|
|
182
221
|
*
|
|
183
222
|
* @example
|
|
184
223
|
* ```ts
|
|
185
224
|
* import * as assert from "node:assert"
|
|
186
225
|
* import { isBigInt } from "effect/Predicate"
|
|
187
226
|
*
|
|
188
|
-
* assert.
|
|
227
|
+
* assert.strictEqual(isBigInt(1n), true)
|
|
189
228
|
*
|
|
190
|
-
* assert.
|
|
229
|
+
* assert.strictEqual(isBigInt(1), false)
|
|
230
|
+
* assert.strictEqual(isBigInt("1"), false)
|
|
191
231
|
* ```
|
|
192
232
|
*
|
|
193
233
|
* @category guards
|
|
@@ -195,16 +235,16 @@ export const isBoolean = input => typeof input === "boolean";
|
|
|
195
235
|
*/
|
|
196
236
|
export const isBigInt = input => typeof input === "bigint";
|
|
197
237
|
/**
|
|
198
|
-
*
|
|
238
|
+
* A refinement that checks if a value is a `symbol`.
|
|
199
239
|
*
|
|
200
240
|
* @example
|
|
201
241
|
* ```ts
|
|
202
242
|
* import * as assert from "node:assert"
|
|
203
243
|
* import { isSymbol } from "effect/Predicate"
|
|
204
244
|
*
|
|
205
|
-
* assert.
|
|
245
|
+
* assert.strictEqual(isSymbol(Symbol.for("a")), true)
|
|
206
246
|
*
|
|
207
|
-
* assert.
|
|
247
|
+
* assert.strictEqual(isSymbol("a"), false)
|
|
208
248
|
* ```
|
|
209
249
|
*
|
|
210
250
|
* @category guards
|
|
@@ -212,19 +252,23 @@ export const isBigInt = input => typeof input === "bigint";
|
|
|
212
252
|
*/
|
|
213
253
|
export const isSymbol = input => typeof input === "symbol";
|
|
214
254
|
// TODO: make public
|
|
215
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* A refinement that checks if a value is a valid `PropertyKey` (a `string`, `number`, or `symbol`).
|
|
257
|
+
* @internal
|
|
258
|
+
*/
|
|
216
259
|
export const isPropertyKey = u => isString(u) || isNumber(u) || isSymbol(u);
|
|
217
260
|
/**
|
|
218
|
-
*
|
|
261
|
+
* A refinement that checks if a value is a `Function`.
|
|
219
262
|
*
|
|
220
263
|
* @example
|
|
221
264
|
* ```ts
|
|
222
265
|
* import * as assert from "node:assert"
|
|
223
266
|
* import { isFunction } from "effect/Predicate"
|
|
224
267
|
*
|
|
225
|
-
* assert.
|
|
268
|
+
* assert.strictEqual(isFunction(() => {}), true)
|
|
269
|
+
* assert.strictEqual(isFunction(isFunction), true)
|
|
226
270
|
*
|
|
227
|
-
* assert.
|
|
271
|
+
* assert.strictEqual(isFunction("function"), false)
|
|
228
272
|
* ```
|
|
229
273
|
*
|
|
230
274
|
* @category guards
|
|
@@ -232,17 +276,17 @@ export const isPropertyKey = u => isString(u) || isNumber(u) || isSymbol(u);
|
|
|
232
276
|
*/
|
|
233
277
|
export const isFunction = isFunction_;
|
|
234
278
|
/**
|
|
235
|
-
*
|
|
279
|
+
* A refinement that checks if a value is `undefined`.
|
|
236
280
|
*
|
|
237
281
|
* @example
|
|
238
282
|
* ```ts
|
|
239
283
|
* import * as assert from "node:assert"
|
|
240
284
|
* import { isUndefined } from "effect/Predicate"
|
|
241
285
|
*
|
|
242
|
-
* assert.
|
|
286
|
+
* assert.strictEqual(isUndefined(undefined), true)
|
|
243
287
|
*
|
|
244
|
-
* assert.
|
|
245
|
-
* assert.
|
|
288
|
+
* assert.strictEqual(isUndefined(null), false)
|
|
289
|
+
* assert.strictEqual(isUndefined("undefined"), false)
|
|
246
290
|
* ```
|
|
247
291
|
*
|
|
248
292
|
* @category guards
|
|
@@ -250,17 +294,17 @@ export const isFunction = isFunction_;
|
|
|
250
294
|
*/
|
|
251
295
|
export const isUndefined = input => input === undefined;
|
|
252
296
|
/**
|
|
253
|
-
*
|
|
297
|
+
* A refinement that checks if a value is not `undefined`.
|
|
254
298
|
*
|
|
255
299
|
* @example
|
|
256
300
|
* ```ts
|
|
257
301
|
* import * as assert from "node:assert"
|
|
258
302
|
* import { isNotUndefined } from "effect/Predicate"
|
|
259
303
|
*
|
|
260
|
-
* assert.
|
|
261
|
-
* assert.
|
|
304
|
+
* assert.strictEqual(isNotUndefined(null), true)
|
|
305
|
+
* assert.strictEqual(isNotUndefined("value"), true)
|
|
262
306
|
*
|
|
263
|
-
* assert.
|
|
307
|
+
* assert.strictEqual(isNotUndefined(undefined), false)
|
|
264
308
|
* ```
|
|
265
309
|
*
|
|
266
310
|
* @category guards
|
|
@@ -268,17 +312,17 @@ export const isUndefined = input => input === undefined;
|
|
|
268
312
|
*/
|
|
269
313
|
export const isNotUndefined = input => input !== undefined;
|
|
270
314
|
/**
|
|
271
|
-
*
|
|
315
|
+
* A refinement that checks if a value is `null`.
|
|
272
316
|
*
|
|
273
317
|
* @example
|
|
274
318
|
* ```ts
|
|
275
319
|
* import * as assert from "node:assert"
|
|
276
320
|
* import { isNull } from "effect/Predicate"
|
|
277
321
|
*
|
|
278
|
-
* assert.
|
|
322
|
+
* assert.strictEqual(isNull(null), true)
|
|
279
323
|
*
|
|
280
|
-
* assert.
|
|
281
|
-
* assert.
|
|
324
|
+
* assert.strictEqual(isNull(undefined), false)
|
|
325
|
+
* assert.strictEqual(isNull("null"), false)
|
|
282
326
|
* ```
|
|
283
327
|
*
|
|
284
328
|
* @category guards
|
|
@@ -286,17 +330,17 @@ export const isNotUndefined = input => input !== undefined;
|
|
|
286
330
|
*/
|
|
287
331
|
export const isNull = input => input === null;
|
|
288
332
|
/**
|
|
289
|
-
*
|
|
333
|
+
* A refinement that checks if a value is not `null`.
|
|
290
334
|
*
|
|
291
335
|
* @example
|
|
292
336
|
* ```ts
|
|
293
337
|
* import * as assert from "node:assert"
|
|
294
338
|
* import { isNotNull } from "effect/Predicate"
|
|
295
339
|
*
|
|
296
|
-
* assert.
|
|
297
|
-
* assert.
|
|
340
|
+
* assert.strictEqual(isNotNull(undefined), true)
|
|
341
|
+
* assert.strictEqual(isNotNull("value"), true)
|
|
298
342
|
*
|
|
299
|
-
* assert.
|
|
343
|
+
* assert.strictEqual(isNotNull(null), false)
|
|
300
344
|
* ```
|
|
301
345
|
*
|
|
302
346
|
* @category guards
|
|
@@ -304,17 +348,16 @@ export const isNull = input => input === null;
|
|
|
304
348
|
*/
|
|
305
349
|
export const isNotNull = input => input !== null;
|
|
306
350
|
/**
|
|
307
|
-
* A
|
|
351
|
+
* A refinement that always returns `false`. The type is narrowed to `never`.
|
|
308
352
|
*
|
|
309
353
|
* @example
|
|
310
354
|
* ```ts
|
|
311
355
|
* import * as assert from "node:assert"
|
|
312
356
|
* import { isNever } from "effect/Predicate"
|
|
313
357
|
*
|
|
314
|
-
* assert.
|
|
315
|
-
* assert.
|
|
316
|
-
* assert.
|
|
317
|
-
* assert.deepStrictEqual(isNever([]), false)
|
|
358
|
+
* assert.strictEqual(isNever(1), false)
|
|
359
|
+
* assert.strictEqual(isNever(null), false)
|
|
360
|
+
* assert.strictEqual(isNever({}), false)
|
|
318
361
|
* ```
|
|
319
362
|
*
|
|
320
363
|
* @category guards
|
|
@@ -322,66 +365,96 @@ export const isNotNull = input => input !== null;
|
|
|
322
365
|
*/
|
|
323
366
|
export const isNever = _ => false;
|
|
324
367
|
/**
|
|
325
|
-
* A
|
|
368
|
+
* A refinement that always returns `true`. The type is narrowed to `unknown`.
|
|
326
369
|
*
|
|
327
370
|
* @example
|
|
328
371
|
* ```ts
|
|
329
372
|
* import * as assert from "node:assert"
|
|
330
373
|
* import { isUnknown } from "effect/Predicate"
|
|
331
374
|
*
|
|
332
|
-
* assert.
|
|
333
|
-
* assert.
|
|
334
|
-
*
|
|
335
|
-
* assert.deepStrictEqual(isUnknown({}), true)
|
|
336
|
-
* assert.deepStrictEqual(isUnknown([]), true)
|
|
375
|
+
* assert.strictEqual(isUnknown(1), true)
|
|
376
|
+
* assert.strictEqual(isUnknown(null), true)
|
|
377
|
+
* assert.strictEqual(isUnknown({}), true)
|
|
337
378
|
* ```
|
|
338
379
|
*
|
|
339
380
|
* @category guards
|
|
340
381
|
* @since 2.0.0
|
|
341
382
|
*/
|
|
342
383
|
export const isUnknown = _ => true;
|
|
343
|
-
/**
|
|
384
|
+
/**
|
|
385
|
+
* Checks if the input is an object or an array.
|
|
386
|
+
* @internal
|
|
387
|
+
*/
|
|
344
388
|
export const isRecordOrArray = input => typeof input === "object" && input !== null;
|
|
345
389
|
/**
|
|
346
|
-
*
|
|
390
|
+
* A refinement that checks if a value is an `object`. Note that in JavaScript,
|
|
391
|
+
* arrays and functions are also considered objects.
|
|
347
392
|
*
|
|
348
393
|
* @example
|
|
349
394
|
* ```ts
|
|
350
395
|
* import * as assert from "node:assert"
|
|
351
396
|
* import { isObject } from "effect/Predicate"
|
|
352
397
|
*
|
|
353
|
-
* assert.
|
|
354
|
-
* assert.
|
|
398
|
+
* assert.strictEqual(isObject({}), true)
|
|
399
|
+
* assert.strictEqual(isObject([]), true)
|
|
400
|
+
* assert.strictEqual(isObject(() => {}), true)
|
|
355
401
|
*
|
|
356
|
-
* assert.
|
|
357
|
-
* assert.
|
|
402
|
+
* assert.strictEqual(isObject(null), false)
|
|
403
|
+
* assert.strictEqual(isObject("hello"), false)
|
|
358
404
|
* ```
|
|
359
405
|
*
|
|
360
406
|
* @category guards
|
|
361
407
|
* @since 2.0.0
|
|
408
|
+
* @see isRecord to check for plain objects (excluding arrays and functions).
|
|
362
409
|
*/
|
|
363
410
|
export const isObject = input => isRecordOrArray(input) || isFunction(input);
|
|
364
411
|
/**
|
|
365
|
-
*
|
|
412
|
+
* A refinement that checks if a value is an object-like value and has a specific property key.
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* ```ts
|
|
416
|
+
* import * as assert from "node:assert"
|
|
417
|
+
* import { hasProperty } from "effect/Predicate"
|
|
418
|
+
*
|
|
419
|
+
* assert.strictEqual(hasProperty({ a: 1 }, "a"), true)
|
|
420
|
+
* assert.strictEqual(hasProperty({ a: 1 }, "b"), false)
|
|
421
|
+
*
|
|
422
|
+
* const value: unknown = { name: "Alice" };
|
|
423
|
+
* if (hasProperty(value, "name")) {
|
|
424
|
+
* // The type of `value` is narrowed to `{ name: unknown }`
|
|
425
|
+
* // and we can safely access `value.name`
|
|
426
|
+
* console.log(value.name)
|
|
427
|
+
* }
|
|
428
|
+
* ```
|
|
366
429
|
*
|
|
367
430
|
* @category guards
|
|
368
431
|
* @since 2.0.0
|
|
369
432
|
*/
|
|
370
433
|
export const hasProperty = /*#__PURE__*/dual(2, (self, property) => isObject(self) && property in self);
|
|
371
434
|
/**
|
|
372
|
-
*
|
|
435
|
+
* A refinement that checks if a value is an object with a `_tag` property
|
|
436
|
+
* that matches the given tag. This is a powerful tool for working with
|
|
437
|
+
* discriminated union types.
|
|
373
438
|
*
|
|
374
439
|
* @example
|
|
375
440
|
* ```ts
|
|
376
441
|
* import * as assert from "node:assert"
|
|
377
442
|
* import { isTagged } from "effect/Predicate"
|
|
378
443
|
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
444
|
+
* type Shape = { _tag: "circle"; radius: number } | { _tag: "square"; side: number }
|
|
445
|
+
*
|
|
446
|
+
* const isCircle = isTagged("circle")
|
|
447
|
+
*
|
|
448
|
+
* const shape1: Shape = { _tag: "circle", radius: 10 }
|
|
449
|
+
* const shape2: Shape = { _tag: "square", side: 5 }
|
|
450
|
+
*
|
|
451
|
+
* assert.strictEqual(isCircle(shape1), true)
|
|
452
|
+
* assert.strictEqual(isCircle(shape2), false)
|
|
453
|
+
*
|
|
454
|
+
* if (isCircle(shape1)) {
|
|
455
|
+
* // shape1 is now narrowed to { _tag: "circle"; radius: number }
|
|
456
|
+
* assert.strictEqual(shape1.radius, 10)
|
|
457
|
+
* }
|
|
385
458
|
* ```
|
|
386
459
|
*
|
|
387
460
|
* @category guards
|
|
@@ -389,55 +462,59 @@ export const hasProperty = /*#__PURE__*/dual(2, (self, property) => isObject(sel
|
|
|
389
462
|
*/
|
|
390
463
|
export const isTagged = /*#__PURE__*/dual(2, (self, tag) => hasProperty(self, "_tag") && self["_tag"] === tag);
|
|
391
464
|
/**
|
|
392
|
-
* A
|
|
465
|
+
* A refinement that checks if a value is either `null` or `undefined`.
|
|
393
466
|
*
|
|
394
467
|
* @example
|
|
395
468
|
* ```ts
|
|
396
469
|
* import * as assert from "node:assert"
|
|
397
470
|
* import { isNullable } from "effect/Predicate"
|
|
398
471
|
*
|
|
399
|
-
* assert.
|
|
400
|
-
* assert.
|
|
472
|
+
* assert.strictEqual(isNullable(null), true)
|
|
473
|
+
* assert.strictEqual(isNullable(undefined), true)
|
|
401
474
|
*
|
|
402
|
-
* assert.
|
|
403
|
-
* assert.
|
|
475
|
+
* assert.strictEqual(isNullable(0), false)
|
|
476
|
+
* assert.strictEqual(isNullable(""), false)
|
|
404
477
|
* ```
|
|
405
478
|
*
|
|
406
479
|
* @category guards
|
|
407
480
|
* @since 2.0.0
|
|
481
|
+
* @see isNotNullable
|
|
408
482
|
*/
|
|
409
483
|
export const isNullable = input => input === null || input === undefined;
|
|
410
484
|
/**
|
|
411
|
-
* A
|
|
485
|
+
* A refinement that checks if a value is neither `null` nor `undefined`.
|
|
486
|
+
* The type is narrowed to `NonNullable<A>`.
|
|
412
487
|
*
|
|
413
488
|
* @example
|
|
414
489
|
* ```ts
|
|
415
490
|
* import * as assert from "node:assert"
|
|
416
491
|
* import { isNotNullable } from "effect/Predicate"
|
|
417
492
|
*
|
|
418
|
-
* assert.
|
|
419
|
-
* assert.
|
|
493
|
+
* assert.strictEqual(isNotNullable(0), true)
|
|
494
|
+
* assert.strictEqual(isNotNullable("hello"), true)
|
|
420
495
|
*
|
|
421
|
-
* assert.
|
|
422
|
-
* assert.
|
|
496
|
+
* assert.strictEqual(isNotNullable(null), false)
|
|
497
|
+
* assert.strictEqual(isNotNullable(undefined), false)
|
|
423
498
|
* ```
|
|
424
499
|
*
|
|
425
500
|
* @category guards
|
|
426
501
|
* @since 2.0.0
|
|
502
|
+
* @see isNullable
|
|
427
503
|
*/
|
|
428
504
|
export const isNotNullable = input => input !== null && input !== undefined;
|
|
429
505
|
/**
|
|
430
|
-
* A
|
|
506
|
+
* A refinement that checks if a value is an instance of `Error`.
|
|
431
507
|
*
|
|
432
508
|
* @example
|
|
433
509
|
* ```ts
|
|
434
510
|
* import * as assert from "node:assert"
|
|
435
511
|
* import { isError } from "effect/Predicate"
|
|
436
512
|
*
|
|
437
|
-
* assert.
|
|
513
|
+
* assert.strictEqual(isError(new Error("boom")), true)
|
|
514
|
+
* assert.strictEqual(isError(new TypeError("boom")), true)
|
|
438
515
|
*
|
|
439
|
-
* assert.
|
|
440
|
-
* assert.
|
|
516
|
+
* assert.strictEqual(isError({ message: "boom" }), false)
|
|
517
|
+
* assert.strictEqual(isError("boom"), false)
|
|
441
518
|
* ```
|
|
442
519
|
*
|
|
443
520
|
* @category guards
|
|
@@ -445,17 +522,17 @@ export const isNotNullable = input => input !== null && input !== undefined;
|
|
|
445
522
|
*/
|
|
446
523
|
export const isError = input => input instanceof Error;
|
|
447
524
|
/**
|
|
448
|
-
* A
|
|
525
|
+
* A refinement that checks if a value is a `Uint8Array`.
|
|
449
526
|
*
|
|
450
527
|
* @example
|
|
451
528
|
* ```ts
|
|
452
529
|
* import * as assert from "node:assert"
|
|
453
530
|
* import { isUint8Array } from "effect/Predicate"
|
|
454
531
|
*
|
|
455
|
-
* assert.
|
|
532
|
+
* assert.strictEqual(isUint8Array(new Uint8Array()), true)
|
|
456
533
|
*
|
|
457
|
-
* assert.
|
|
458
|
-
* assert.
|
|
534
|
+
* assert.strictEqual(isUint8Array(new Uint16Array()), false)
|
|
535
|
+
* assert.strictEqual(isUint8Array([1, 2, 3]), false)
|
|
459
536
|
* ```
|
|
460
537
|
*
|
|
461
538
|
* @category guards
|
|
@@ -463,17 +540,17 @@ export const isError = input => input instanceof Error;
|
|
|
463
540
|
*/
|
|
464
541
|
export const isUint8Array = input => input instanceof Uint8Array;
|
|
465
542
|
/**
|
|
466
|
-
* A
|
|
543
|
+
* A refinement that checks if a value is a `Date` object.
|
|
467
544
|
*
|
|
468
545
|
* @example
|
|
469
546
|
* ```ts
|
|
470
547
|
* import * as assert from "node:assert"
|
|
471
548
|
* import { isDate } from "effect/Predicate"
|
|
472
549
|
*
|
|
473
|
-
* assert.
|
|
550
|
+
* assert.strictEqual(isDate(new Date()), true)
|
|
474
551
|
*
|
|
475
|
-
* assert.
|
|
476
|
-
* assert.
|
|
552
|
+
* assert.strictEqual(isDate(Date.now()), false) // `Date.now()` returns a number
|
|
553
|
+
* assert.strictEqual(isDate("2023-01-01"), false)
|
|
477
554
|
* ```
|
|
478
555
|
*
|
|
479
556
|
* @category guards
|
|
@@ -481,18 +558,20 @@ export const isUint8Array = input => input instanceof Uint8Array;
|
|
|
481
558
|
*/
|
|
482
559
|
export const isDate = input => input instanceof Date;
|
|
483
560
|
/**
|
|
484
|
-
* A
|
|
561
|
+
* A refinement that checks if a value is an `Iterable`.
|
|
562
|
+
* Many built-in types are iterable, such as `Array`, `string`, `Map`, and `Set`.
|
|
485
563
|
*
|
|
486
564
|
* @example
|
|
487
565
|
* ```ts
|
|
488
566
|
* import * as assert from "node:assert"
|
|
489
567
|
* import { isIterable } from "effect/Predicate"
|
|
490
568
|
*
|
|
491
|
-
* assert.
|
|
492
|
-
* assert.
|
|
569
|
+
* assert.strictEqual(isIterable([]), true)
|
|
570
|
+
* assert.strictEqual(isIterable("hello"), true)
|
|
571
|
+
* assert.strictEqual(isIterable(new Set()), true)
|
|
493
572
|
*
|
|
494
|
-
* assert.
|
|
495
|
-
* assert.
|
|
573
|
+
* assert.strictEqual(isIterable({}), false)
|
|
574
|
+
* assert.strictEqual(isIterable(123), false)
|
|
496
575
|
* ```
|
|
497
576
|
*
|
|
498
577
|
* @category guards
|
|
@@ -500,42 +579,44 @@ export const isDate = input => input instanceof Date;
|
|
|
500
579
|
*/
|
|
501
580
|
export const isIterable = input => hasProperty(input, Symbol.iterator);
|
|
502
581
|
/**
|
|
503
|
-
* A
|
|
582
|
+
* A refinement that checks if a value is a record (i.e., a plain object).
|
|
583
|
+
* This check returns `false` for arrays, `null`, and functions.
|
|
504
584
|
*
|
|
505
585
|
* @example
|
|
506
586
|
* ```ts
|
|
507
587
|
* import * as assert from "node:assert"
|
|
508
588
|
* import { isRecord } from "effect/Predicate"
|
|
509
589
|
*
|
|
510
|
-
* assert.
|
|
511
|
-
* assert.
|
|
590
|
+
* assert.strictEqual(isRecord({}), true)
|
|
591
|
+
* assert.strictEqual(isRecord({ a: 1 }), true)
|
|
512
592
|
*
|
|
513
|
-
* assert.
|
|
514
|
-
* assert.
|
|
515
|
-
* assert.
|
|
516
|
-
* assert.
|
|
517
|
-
* assert.deepStrictEqual(isRecord(() => null), false)
|
|
593
|
+
* assert.strictEqual(isRecord([]), false)
|
|
594
|
+
* assert.strictEqual(isRecord(new Date()), false)
|
|
595
|
+
* assert.strictEqual(isRecord(null), false)
|
|
596
|
+
* assert.strictEqual(isRecord(() => null), false)
|
|
518
597
|
* ```
|
|
519
598
|
*
|
|
520
599
|
* @category guards
|
|
521
600
|
* @since 2.0.0
|
|
601
|
+
* @see isObject
|
|
522
602
|
*/
|
|
523
603
|
export const isRecord = input => isRecordOrArray(input) && !Array.isArray(input);
|
|
524
604
|
/**
|
|
525
|
-
* A
|
|
605
|
+
* A refinement that checks if a value is a readonly record (i.e., a plain object).
|
|
606
|
+
* This check returns `false` for arrays, `null`, and functions.
|
|
607
|
+
*
|
|
608
|
+
* This is an alias for `isRecord`.
|
|
526
609
|
*
|
|
527
610
|
* @example
|
|
528
611
|
* ```ts
|
|
529
612
|
* import * as assert from "node:assert"
|
|
530
613
|
* import { isReadonlyRecord } from "effect/Predicate"
|
|
531
614
|
*
|
|
532
|
-
* assert.
|
|
533
|
-
* assert.
|
|
615
|
+
* assert.strictEqual(isReadonlyRecord({}), true)
|
|
616
|
+
* assert.strictEqual(isReadonlyRecord({ a: 1 }), true)
|
|
534
617
|
*
|
|
535
|
-
* assert.
|
|
536
|
-
* assert.
|
|
537
|
-
* assert.deepStrictEqual(isReadonlyRecord(null), false)
|
|
538
|
-
* assert.deepStrictEqual(isReadonlyRecord(undefined), false)
|
|
618
|
+
* assert.strictEqual(isReadonlyRecord([]), false)
|
|
619
|
+
* assert.strictEqual(isReadonlyRecord(null), false)
|
|
539
620
|
* ```
|
|
540
621
|
*
|
|
541
622
|
* @category guards
|
|
@@ -543,36 +624,58 @@ export const isRecord = input => isRecordOrArray(input) && !Array.isArray(input)
|
|
|
543
624
|
*/
|
|
544
625
|
export const isReadonlyRecord = isRecord;
|
|
545
626
|
/**
|
|
546
|
-
* A
|
|
627
|
+
* A refinement that checks if a value is a `Promise`. It performs a duck-typing check
|
|
628
|
+
* for `.then` and `.catch` methods.
|
|
547
629
|
*
|
|
548
630
|
* @example
|
|
549
631
|
* ```ts
|
|
550
632
|
* import * as assert from "node:assert"
|
|
551
633
|
* import { isPromise } from "effect/Predicate"
|
|
552
634
|
*
|
|
553
|
-
* assert.
|
|
554
|
-
* assert.
|
|
635
|
+
* assert.strictEqual(isPromise(Promise.resolve(1)), true)
|
|
636
|
+
* assert.strictEqual(isPromise(new Promise(() => {})), true)
|
|
637
|
+
*
|
|
638
|
+
* assert.strictEqual(isPromise({ then() {} }), false) // Missing .catch
|
|
639
|
+
* assert.strictEqual(isPromise({}), false)
|
|
555
640
|
* ```
|
|
556
641
|
*
|
|
557
642
|
* @category guards
|
|
558
643
|
* @since 2.0.0
|
|
644
|
+
* @see isPromiseLike
|
|
559
645
|
*/
|
|
560
646
|
export const isPromise = input => hasProperty(input, "then") && "catch" in input && isFunction(input.then) && isFunction(input.catch);
|
|
561
647
|
/**
|
|
648
|
+
* A refinement that checks if a value is `PromiseLike`. It performs a duck-typing
|
|
649
|
+
* check for a `.then` method.
|
|
650
|
+
*
|
|
651
|
+
* @example
|
|
652
|
+
* ```ts
|
|
653
|
+
* import * as assert from "node:assert"
|
|
654
|
+
* import { isPromiseLike } from "effect/Predicate"
|
|
655
|
+
*
|
|
656
|
+
* assert.strictEqual(isPromiseLike(Promise.resolve(1)), true)
|
|
657
|
+
* assert.strictEqual(isPromiseLike({ then: () => {} }), true)
|
|
658
|
+
*
|
|
659
|
+
* assert.strictEqual(isPromiseLike({}), false)
|
|
660
|
+
* ```
|
|
661
|
+
*
|
|
562
662
|
* @category guards
|
|
563
663
|
* @since 2.0.0
|
|
664
|
+
* @see isPromise
|
|
564
665
|
*/
|
|
565
666
|
export const isPromiseLike = input => hasProperty(input, "then") && isFunction(input.then);
|
|
566
667
|
/**
|
|
567
|
-
*
|
|
668
|
+
* A refinement that checks if a value is a `RegExp`.
|
|
568
669
|
*
|
|
569
670
|
* @example
|
|
570
671
|
* ```ts
|
|
571
672
|
* import * as assert from "node:assert"
|
|
572
673
|
* import { Predicate } from "effect"
|
|
573
674
|
*
|
|
574
|
-
* assert.
|
|
575
|
-
* assert.
|
|
675
|
+
* assert.strictEqual(Predicate.isRegExp(/a/), true)
|
|
676
|
+
* assert.strictEqual(Predicate.isRegExp(new RegExp("a")), true)
|
|
677
|
+
*
|
|
678
|
+
* assert.strictEqual(Predicate.isRegExp("/a/"), false)
|
|
576
679
|
* ```
|
|
577
680
|
*
|
|
578
681
|
* @category guards
|
|
@@ -580,17 +683,53 @@ export const isPromiseLike = input => hasProperty(input, "then") && isFunction(i
|
|
|
580
683
|
*/
|
|
581
684
|
export const isRegExp = input => input instanceof RegExp;
|
|
582
685
|
/**
|
|
686
|
+
* Composes a `Refinement` with another `Refinement` or `Predicate`.
|
|
687
|
+
*
|
|
688
|
+
* This can be used to chain checks. The first refinement is applied, and if it
|
|
689
|
+
* passes, the second check is applied to the same value, potentially refining
|
|
690
|
+
* the type further.
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* ```ts
|
|
694
|
+
* import { Predicate } from "effect"
|
|
695
|
+
* import * as assert from "node:assert"
|
|
696
|
+
*
|
|
697
|
+
* const isString = (u: unknown): u is string => typeof u === "string"
|
|
698
|
+
* const minLength = (n: number) => (s: string): boolean => s.length >= n
|
|
699
|
+
*
|
|
700
|
+
* // Create a refinement that checks for a string with a minimum length of 3
|
|
701
|
+
* const isLongString = Predicate.compose(isString, minLength(3))
|
|
702
|
+
*
|
|
703
|
+
* let value: unknown = "hello"
|
|
704
|
+
*
|
|
705
|
+
* assert.strictEqual(isLongString(value), true)
|
|
706
|
+
* if (isLongString(value)) {
|
|
707
|
+
* // value is narrowed to string
|
|
708
|
+
* assert.strictEqual(value.toUpperCase(), "HELLO")
|
|
709
|
+
* }
|
|
710
|
+
* assert.strictEqual(isLongString("hi"), false)
|
|
711
|
+
* ```
|
|
712
|
+
*
|
|
583
713
|
* @since 2.0.0
|
|
584
714
|
*/
|
|
585
715
|
export const compose = /*#__PURE__*/dual(2, (ab, bc) => a => ab(a) && bc(a));
|
|
586
716
|
/**
|
|
717
|
+
* Combines two predicates to test a tuple of two values. The first predicate tests the
|
|
718
|
+
* first element of the tuple, and the second predicate tests the second element.
|
|
719
|
+
*
|
|
587
720
|
* @category combining
|
|
588
721
|
* @since 2.0.0
|
|
589
722
|
*/
|
|
590
723
|
export const product = (self, that) => ([a, b]) => self(a) && that(b);
|
|
591
724
|
/**
|
|
725
|
+
* Takes an iterable of predicates and returns a new predicate that tests an array of values.
|
|
726
|
+
* The new predicate returns `true` if each predicate at a given index is satisfied by the
|
|
727
|
+
* value at the same index in the array. The check stops at the length of the shorter of
|
|
728
|
+
* the two iterables (predicates or values).
|
|
729
|
+
*
|
|
592
730
|
* @category combining
|
|
593
731
|
* @since 2.0.0
|
|
732
|
+
* @see tuple for a more powerful, variadic version.
|
|
594
733
|
*/
|
|
595
734
|
export const all = collection => {
|
|
596
735
|
return as => {
|
|
@@ -608,6 +747,9 @@ export const all = collection => {
|
|
|
608
747
|
};
|
|
609
748
|
};
|
|
610
749
|
/**
|
|
750
|
+
* Combines a predicate for a single value and an iterable of predicates for the rest of an array.
|
|
751
|
+
* Useful for checking the head and tail of an array separately.
|
|
752
|
+
*
|
|
611
753
|
* @category combining
|
|
612
754
|
* @since 2.0.0
|
|
613
755
|
*/
|
|
@@ -616,22 +758,67 @@ export const productMany = (self, collection) => {
|
|
|
616
758
|
return ([head, ...tail]) => self(head) === false ? false : rest(tail);
|
|
617
759
|
};
|
|
618
760
|
/**
|
|
619
|
-
*
|
|
761
|
+
* Combines an array of predicates into a single predicate that tests an array of values.
|
|
762
|
+
* This function is highly type-aware and will produce a `Refinement` if any of the provided
|
|
763
|
+
* predicates are `Refinement`s, allowing for powerful type-narrowing of tuples.
|
|
764
|
+
*
|
|
765
|
+
* - If all predicates are `Predicate<T>`, the result is `Predicate<[T, T, ...]>`.
|
|
766
|
+
* - If any predicate is a `Refinement<A, B>`, the result is a `Refinement` that narrows
|
|
767
|
+
* the input tuple type to a more specific tuple type.
|
|
620
768
|
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
769
|
+
* @example
|
|
770
|
+
* ```ts
|
|
771
|
+
* import * as assert from "node:assert"
|
|
772
|
+
* import { Predicate } from "effect"
|
|
773
|
+
*
|
|
774
|
+
* const isString = (u: unknown): u is string => typeof u === "string"
|
|
775
|
+
* const isNumber = (u: unknown): u is number => typeof u === "number"
|
|
776
|
+
*
|
|
777
|
+
* // Create a refinement for a [string, number] tuple
|
|
778
|
+
* const isStringNumberTuple = Predicate.tuple(isString, isNumber)
|
|
779
|
+
*
|
|
780
|
+
* const value: [unknown, unknown] = ["hello", 123]
|
|
781
|
+
* if (isStringNumberTuple(value)) {
|
|
782
|
+
* // value is narrowed to [string, number]
|
|
783
|
+
* const [s, n] = value
|
|
784
|
+
* assert.strictEqual(s.toUpperCase(), "HELLO")
|
|
785
|
+
* assert.strictEqual(n.toFixed(2), "123.00")
|
|
786
|
+
* }
|
|
787
|
+
* assert.strictEqual(isStringNumberTuple(["hello", "123"]), false)
|
|
625
788
|
* ```
|
|
626
789
|
*
|
|
627
790
|
* @since 2.0.0
|
|
628
791
|
*/
|
|
629
792
|
export const tuple = (...elements) => all(elements);
|
|
630
793
|
/**
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
794
|
+
* Combines a record of predicates into a single predicate that tests a record of values.
|
|
795
|
+
* This function is highly type-aware and will produce a `Refinement` if any of the provided
|
|
796
|
+
* predicates are `Refinement`s, allowing for powerful type-narrowing of structs.
|
|
797
|
+
*
|
|
798
|
+
* - If all predicates are `Predicate<T>`, the result is `Predicate<{ k: T, ... }>`.
|
|
799
|
+
* - If any predicate is a `Refinement<A, B>`, the result is a `Refinement` that narrows
|
|
800
|
+
* the input record type to a more specific record type.
|
|
801
|
+
*
|
|
802
|
+
* @example
|
|
803
|
+
* ```ts
|
|
804
|
+
* import * as assert from "node:assert"
|
|
805
|
+
* import { Predicate } from "effect"
|
|
806
|
+
*
|
|
807
|
+
* const isString = (u: unknown): u is string => typeof u === "string"
|
|
808
|
+
* const isNumber = (u: unknown): u is number => typeof u === "number"
|
|
809
|
+
*
|
|
810
|
+
* const personPredicate = Predicate.struct({
|
|
811
|
+
* name: isString,
|
|
812
|
+
* age: isNumber
|
|
813
|
+
* })
|
|
814
|
+
*
|
|
815
|
+
* const value: { name: unknown; age: unknown } = { name: "Alice", age: 30 }
|
|
816
|
+
* if (personPredicate(value)) {
|
|
817
|
+
* // value is narrowed to { name: string; age: number }
|
|
818
|
+
* assert.strictEqual(value.name.toUpperCase(), "ALICE")
|
|
819
|
+
* assert.strictEqual(value.age.toFixed(0), "30")
|
|
820
|
+
* }
|
|
821
|
+
* assert.strictEqual(personPredicate({ name: "Bob", age: "40" }), false)
|
|
635
822
|
* ```
|
|
636
823
|
*
|
|
637
824
|
* @since 2.0.0
|
|
@@ -648,18 +835,21 @@ export const struct = fields => {
|
|
|
648
835
|
};
|
|
649
836
|
};
|
|
650
837
|
/**
|
|
651
|
-
*
|
|
838
|
+
* Returns a new predicate that is the logical negation of the given predicate.
|
|
839
|
+
*
|
|
840
|
+
* **Note**: If the input is a `Refinement`, the resulting predicate will be a
|
|
841
|
+
* simple `Predicate`, as TypeScript cannot infer the negative type.
|
|
652
842
|
*
|
|
653
843
|
* @example
|
|
654
844
|
* ```ts
|
|
655
845
|
* import * as assert from "node:assert"
|
|
656
846
|
* import { Predicate, Number } from "effect"
|
|
657
847
|
*
|
|
658
|
-
* const
|
|
848
|
+
* const isNonPositive = Predicate.not(Number.greaterThan(0))
|
|
659
849
|
*
|
|
660
|
-
* assert.
|
|
661
|
-
* assert.
|
|
662
|
-
* assert.
|
|
850
|
+
* assert.strictEqual(isNonPositive(-1), true)
|
|
851
|
+
* assert.strictEqual(isNonPositive(0), true)
|
|
852
|
+
* assert.strictEqual(isNonPositive(1), false)
|
|
663
853
|
* ```
|
|
664
854
|
*
|
|
665
855
|
* @category combinators
|
|
@@ -667,18 +857,31 @@ export const struct = fields => {
|
|
|
667
857
|
*/
|
|
668
858
|
export const not = self => a => !self(a);
|
|
669
859
|
/**
|
|
670
|
-
* Combines two predicates
|
|
860
|
+
* Combines two predicates with a logical "OR". The resulting predicate returns `true`
|
|
861
|
+
* if at least one of the predicates returns `true`.
|
|
862
|
+
*
|
|
863
|
+
* If both predicates are `Refinement`s, the resulting predicate is a `Refinement` to the
|
|
864
|
+
* union of their target types (`B | C`).
|
|
671
865
|
*
|
|
672
866
|
* @example
|
|
673
867
|
* ```ts
|
|
674
868
|
* import * as assert from "node:assert"
|
|
675
|
-
* import { Predicate
|
|
869
|
+
* import { Predicate } from "effect"
|
|
870
|
+
*
|
|
871
|
+
* const isString = (u: unknown): u is string => typeof u === "string"
|
|
872
|
+
* const isNumber = (u: unknown): u is number => typeof u === "number"
|
|
873
|
+
*
|
|
874
|
+
* const isStringOrNumber = Predicate.or(isString, isNumber)
|
|
676
875
|
*
|
|
677
|
-
*
|
|
876
|
+
* assert.strictEqual(isStringOrNumber("hello"), true)
|
|
877
|
+
* assert.strictEqual(isStringOrNumber(123), true)
|
|
878
|
+
* assert.strictEqual(isStringOrNumber(null), false)
|
|
678
879
|
*
|
|
679
|
-
*
|
|
680
|
-
*
|
|
681
|
-
*
|
|
880
|
+
* const value: unknown = "world"
|
|
881
|
+
* if (isStringOrNumber(value)) {
|
|
882
|
+
* // value is narrowed to string | number
|
|
883
|
+
* console.log(value)
|
|
884
|
+
* }
|
|
682
885
|
* ```
|
|
683
886
|
*
|
|
684
887
|
* @category combinators
|
|
@@ -686,21 +889,34 @@ export const not = self => a => !self(a);
|
|
|
686
889
|
*/
|
|
687
890
|
export const or = /*#__PURE__*/dual(2, (self, that) => a => self(a) || that(a));
|
|
688
891
|
/**
|
|
689
|
-
* Combines two predicates
|
|
892
|
+
* Combines two predicates with a logical "AND". The resulting predicate returns `true`
|
|
893
|
+
* only if both of the predicates return `true`.
|
|
894
|
+
*
|
|
895
|
+
* If both predicates are `Refinement`s, the resulting predicate is a `Refinement` to the
|
|
896
|
+
* intersection of their target types (`B & C`).
|
|
690
897
|
*
|
|
691
898
|
* @example
|
|
692
899
|
* ```ts
|
|
693
900
|
* import * as assert from "node:assert"
|
|
694
901
|
* import { Predicate } from "effect"
|
|
695
902
|
*
|
|
696
|
-
*
|
|
697
|
-
*
|
|
903
|
+
* type Person = { name: string }
|
|
904
|
+
* type Employee = { id: number }
|
|
698
905
|
*
|
|
699
|
-
* const
|
|
906
|
+
* const hasName = (u: unknown): u is Person => Predicate.hasProperty(u, "name") && typeof (u as any).name === "string"
|
|
907
|
+
* const hasId = (u: unknown): u is Employee => Predicate.hasProperty(u, "id") && typeof (u as any).id === "number"
|
|
700
908
|
*
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
*
|
|
909
|
+
* const isPersonAndEmployee = Predicate.and(hasName, hasId)
|
|
910
|
+
*
|
|
911
|
+
* const val: unknown = { name: "Alice", id: 123 }
|
|
912
|
+
* if (isPersonAndEmployee(val)) {
|
|
913
|
+
* // val is narrowed to Person & Employee
|
|
914
|
+
* assert.strictEqual(val.name, "Alice")
|
|
915
|
+
* assert.strictEqual(val.id, 123)
|
|
916
|
+
* }
|
|
917
|
+
*
|
|
918
|
+
* assert.strictEqual(isPersonAndEmployee({ name: "Bob" }), false) // Missing id
|
|
919
|
+
* assert.strictEqual(isPersonAndEmployee({ id: 456 }), false) // Missing name
|
|
704
920
|
* ```
|
|
705
921
|
*
|
|
706
922
|
* @category combinators
|
|
@@ -708,57 +924,107 @@ export const or = /*#__PURE__*/dual(2, (self, that) => a => self(a) || that(a));
|
|
|
708
924
|
*/
|
|
709
925
|
export const and = /*#__PURE__*/dual(2, (self, that) => a => self(a) && that(a));
|
|
710
926
|
/**
|
|
927
|
+
* Combines two predicates with a logical "XOR" (exclusive OR). The resulting predicate
|
|
928
|
+
* returns `true` if one of the predicates returns `true`, but not both.
|
|
929
|
+
*
|
|
930
|
+
* @example
|
|
931
|
+
* ```ts
|
|
932
|
+
* import * as assert from "node:assert"
|
|
933
|
+
* import { Predicate } from "effect"
|
|
934
|
+
*
|
|
935
|
+
* const isPositive = (n: number) => n > 0
|
|
936
|
+
* const isEven = (n: number) => n % 2 === 0
|
|
937
|
+
*
|
|
938
|
+
* const isPositiveXorEven = Predicate.xor(isPositive, isEven)
|
|
939
|
+
*
|
|
940
|
+
* assert.strictEqual(isPositiveXorEven(4), false) // both true -> false
|
|
941
|
+
* assert.strictEqual(isPositiveXorEven(3), true) // one true -> true
|
|
942
|
+
* assert.strictEqual(isPositiveXorEven(-2), true) // one true -> true
|
|
943
|
+
* assert.strictEqual(isPositiveXorEven(-1), false) // both false -> false
|
|
944
|
+
* ```
|
|
945
|
+
*
|
|
711
946
|
* @category combinators
|
|
712
947
|
* @since 2.0.0
|
|
713
948
|
*/
|
|
714
949
|
export const xor = /*#__PURE__*/dual(2, (self, that) => a => self(a) !== that(a));
|
|
715
950
|
/**
|
|
951
|
+
* Combines two predicates with a logical "EQV" (equivalence). The resulting predicate
|
|
952
|
+
* returns `true` if both predicates return the same boolean value (both `true` or both `false`).
|
|
953
|
+
*
|
|
954
|
+
* @example
|
|
955
|
+
* ```ts
|
|
956
|
+
* import * as assert from "node:assert"
|
|
957
|
+
* import { Predicate } from "effect"
|
|
958
|
+
*
|
|
959
|
+
* const isPositive = (n: number) => n > 0
|
|
960
|
+
* const isEven = (n: number) => n % 2 === 0
|
|
961
|
+
*
|
|
962
|
+
* const isPositiveEqvEven = Predicate.eqv(isPositive, isEven)
|
|
963
|
+
*
|
|
964
|
+
* assert.strictEqual(isPositiveEqvEven(4), true) // both true -> true
|
|
965
|
+
* assert.strictEqual(isPositiveEqvEven(3), false) // different -> false
|
|
966
|
+
* assert.strictEqual(isPositiveEqvEven(-2), false) // different -> false
|
|
967
|
+
* assert.strictEqual(isPositiveEqvEven(-1), true) // both false -> true
|
|
968
|
+
* ```
|
|
969
|
+
*
|
|
716
970
|
* @category combinators
|
|
717
971
|
* @since 2.0.0
|
|
718
972
|
*/
|
|
719
973
|
export const eqv = /*#__PURE__*/dual(2, (self, that) => a => self(a) === that(a));
|
|
720
974
|
/**
|
|
721
|
-
*
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
* true. In simpler terms, `p implies q` can be interpreted as "if p then q". If
|
|
725
|
-
* the first predicate holds, then the second predicate must hold
|
|
726
|
-
* for the given context.
|
|
975
|
+
* Creates a predicate that represents a logical "if-then" rule.
|
|
976
|
+
*
|
|
977
|
+
* Think of it as a conditional promise: **"If `antecedent` holds true, then I promise `consequent` will also be true."**
|
|
727
978
|
*
|
|
728
|
-
*
|
|
979
|
+
* This function is invaluable for defining complex validation logic where one condition dictates another.
|
|
729
980
|
*
|
|
730
|
-
*
|
|
731
|
-
* because the outcome of the consequent cannot be determined.
|
|
981
|
+
* ### How It Works
|
|
732
982
|
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
* It proves especially helpful in defining property tests.
|
|
983
|
+
* The rule only fails (returns `false`) when the "if" part is `true`, but the "then" part is `false`.
|
|
984
|
+
* In all other cases, the promise is considered kept, and the result is `true`.
|
|
736
985
|
*
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
986
|
+
* This includes the concept of **"vacuous truth"**: if the "if" part is `false`, the rule doesn't apply,
|
|
987
|
+
* so the promise isn't broken, and the result is `true`. (e.g., "If it rains, I'll bring an umbrella."
|
|
988
|
+
* If it doesn't rain, you haven't broken your promise, no matter what).
|
|
989
|
+
*
|
|
990
|
+
* ### Key Details
|
|
991
|
+
*
|
|
992
|
+
* - **Logical Equivalence**: `implies(p, q)` is the same as `not(p).or(q)`, or simply `!p || q`
|
|
993
|
+
* in plain JavaScript. This can be a helpful way to reason about its behavior.
|
|
994
|
+
*
|
|
995
|
+
* - **Type-Safety Warning**: This function always returns a `Predicate`, never a type-narrowing
|
|
996
|
+
* `Refinement`. A `true` result doesn't guarantee the `consequent` passed (it could be `true`
|
|
997
|
+
* simply because the `antecedent` was `false`), so it cannot be used to safely narrow a type.
|
|
740
998
|
*
|
|
741
999
|
* @example
|
|
742
1000
|
* ```ts
|
|
1001
|
+
* // Rule: A user can only be an admin if they also belong to the "staff" group.
|
|
743
1002
|
* import * as assert from "node:assert"
|
|
744
1003
|
* import { Predicate } from "effect"
|
|
745
1004
|
*
|
|
746
|
-
* type
|
|
747
|
-
*
|
|
748
|
-
*
|
|
749
|
-
* readonly c: number
|
|
1005
|
+
* type User = {
|
|
1006
|
+
* isStaff: boolean
|
|
1007
|
+
* isAdmin: boolean
|
|
750
1008
|
* }
|
|
751
1009
|
*
|
|
752
|
-
* const
|
|
753
|
-
* // antecedent
|
|
754
|
-
* (
|
|
755
|
-
* // consequent
|
|
756
|
-
* (
|
|
1010
|
+
* const isValidUserPermission = Predicate.implies(
|
|
1011
|
+
* // antecedent: "if" the user is an admin...
|
|
1012
|
+
* (user: User) => user.isAdmin,
|
|
1013
|
+
* // consequent: "then" they must be staff.
|
|
1014
|
+
* (user: User) => user.isStaff
|
|
757
1015
|
* )
|
|
758
1016
|
*
|
|
759
|
-
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
1017
|
+
* // A non-admin who is not staff. Rule doesn't apply (antecedent is false).
|
|
1018
|
+
* assert.strictEqual(isValidUserPermission({ isStaff: false, isAdmin: false }), true)
|
|
1019
|
+
*
|
|
1020
|
+
* // A staff member who is not an admin. Rule doesn't apply (antecedent is false).
|
|
1021
|
+
* assert.strictEqual(isValidUserPermission({ isStaff: true, isAdmin: false }), true)
|
|
1022
|
+
*
|
|
1023
|
+
* // An admin who is also staff. The rule was followed.
|
|
1024
|
+
* assert.strictEqual(isValidUserPermission({ isStaff: true, isAdmin: true }), true)
|
|
1025
|
+
*
|
|
1026
|
+
* // An admin who is NOT staff. The rule was broken!
|
|
1027
|
+
* assert.strictEqual(isValidUserPermission({ isStaff: false, isAdmin: true }), false)
|
|
762
1028
|
* ```
|
|
763
1029
|
*
|
|
764
1030
|
* @category combinators
|
|
@@ -766,18 +1032,47 @@ export const eqv = /*#__PURE__*/dual(2, (self, that) => a => self(a) === that(a)
|
|
|
766
1032
|
*/
|
|
767
1033
|
export const implies = /*#__PURE__*/dual(2, (antecedent, consequent) => a => antecedent(a) ? consequent(a) : true);
|
|
768
1034
|
/**
|
|
1035
|
+
* Combines two predicates with a logical "NOR" (negated OR). The resulting predicate
|
|
1036
|
+
* returns `true` only if both predicates return `false`.
|
|
1037
|
+
* This is equivalent to `not(or(p, q))`.
|
|
1038
|
+
*
|
|
769
1039
|
* @category combinators
|
|
770
1040
|
* @since 2.0.0
|
|
771
1041
|
*/
|
|
772
1042
|
export const nor = /*#__PURE__*/dual(2, (self, that) => a => !(self(a) || that(a)));
|
|
773
1043
|
/**
|
|
1044
|
+
* Combines two predicates with a logical "NAND" (negated AND). The resulting predicate
|
|
1045
|
+
* returns `true` if at least one of the predicates returns `false`.
|
|
1046
|
+
* This is equivalent to `not(and(p, q))`.
|
|
1047
|
+
*
|
|
774
1048
|
* @category combinators
|
|
775
1049
|
* @since 2.0.0
|
|
776
1050
|
*/
|
|
777
1051
|
export const nand = /*#__PURE__*/dual(2, (self, that) => a => !(self(a) && that(a)));
|
|
778
1052
|
/**
|
|
1053
|
+
* Takes an iterable of predicates and returns a new predicate. The new predicate
|
|
1054
|
+
* returns `true` if all predicates in the collection return `true` for a given value.
|
|
1055
|
+
*
|
|
1056
|
+
* This is like `Array.prototype.every` but for a collection of predicates.
|
|
1057
|
+
*
|
|
1058
|
+
* @example
|
|
1059
|
+
* ```ts
|
|
1060
|
+
* import * as assert from "node:assert"
|
|
1061
|
+
* import { Predicate } from "effect"
|
|
1062
|
+
*
|
|
1063
|
+
* const isPositive = (n: number) => n > 0
|
|
1064
|
+
* const isEven = (n: number) => n % 2 === 0
|
|
1065
|
+
*
|
|
1066
|
+
* const isPositiveAndEven = Predicate.every([isPositive, isEven])
|
|
1067
|
+
*
|
|
1068
|
+
* assert.strictEqual(isPositiveAndEven(4), true)
|
|
1069
|
+
* assert.strictEqual(isPositiveAndEven(3), false)
|
|
1070
|
+
* assert.strictEqual(isPositiveAndEven(-2), false)
|
|
1071
|
+
* ```
|
|
1072
|
+
*
|
|
779
1073
|
* @category elements
|
|
780
1074
|
* @since 2.0.0
|
|
1075
|
+
* @see some
|
|
781
1076
|
*/
|
|
782
1077
|
export const every = collection => a => {
|
|
783
1078
|
for (const p of collection) {
|
|
@@ -788,8 +1083,29 @@ export const every = collection => a => {
|
|
|
788
1083
|
return true;
|
|
789
1084
|
};
|
|
790
1085
|
/**
|
|
1086
|
+
* Takes an iterable of predicates and returns a new predicate. The new predicate
|
|
1087
|
+
* returns `true` if at least one predicate in the collection returns `true` for a given value.
|
|
1088
|
+
*
|
|
1089
|
+
* This is like `Array.prototype.some` but for a collection of predicates.
|
|
1090
|
+
*
|
|
1091
|
+
* @example
|
|
1092
|
+
* ```ts
|
|
1093
|
+
* import * as assert from "node:assert"
|
|
1094
|
+
* import { Predicate } from "effect"
|
|
1095
|
+
*
|
|
1096
|
+
* const isNegative = (n: number) => n < 0
|
|
1097
|
+
* const isOdd = (n: number) => n % 2 !== 0
|
|
1098
|
+
*
|
|
1099
|
+
* const isNegativeOrOdd = Predicate.some([isNegative, isOdd])
|
|
1100
|
+
*
|
|
1101
|
+
* assert.strictEqual(isNegativeOrOdd(-2), true) // isNegative is true
|
|
1102
|
+
* assert.strictEqual(isNegativeOrOdd(3), true) // isOdd is true
|
|
1103
|
+
* assert.strictEqual(isNegativeOrOdd(4), false) // both are false
|
|
1104
|
+
* ```
|
|
1105
|
+
*
|
|
791
1106
|
* @category elements
|
|
792
1107
|
* @since 2.0.0
|
|
1108
|
+
* @see every
|
|
793
1109
|
*/
|
|
794
1110
|
export const some = collection => a => {
|
|
795
1111
|
for (const p of collection) {
|