effect 3.16.13 → 3.16.15

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