@typed/guard 1.0.0-beta.0 → 1.0.0-beta.10
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/LICENSE +21 -0
- package/README.md +41 -17
- package/dist/getGuard.d.ts +24 -0
- package/dist/getGuard.d.ts.map +1 -0
- package/dist/getGuard.js +37 -0
- package/dist/index.d.ts +510 -45
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +376 -22
- package/examples/basic.ts +23 -0
- package/package.json +33 -11
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -314
- package/src/index.test.ts +0 -370
- package/src/index.ts +0 -661
- package/tsconfig.json +0 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
+
import type * as Arr from "effect/Array";
|
|
4
5
|
import type * as Cause from "effect/Cause";
|
|
5
6
|
import * as Effect from "effect/Effect";
|
|
6
7
|
import type * as Layer from "effect/Layer";
|
|
7
8
|
import * as Option from "effect/Option";
|
|
8
9
|
import type * as Predicate from "effect/Predicate";
|
|
9
10
|
import * as Schema from "effect/Schema";
|
|
10
|
-
import type * as
|
|
11
|
+
import type * as Context from "effect/Context";
|
|
12
|
+
import type { ExcludeTag, ExtractTag, NoInfer, Tags } from "effect/Types";
|
|
13
|
+
export { getGuard } from "./getGuard.js";
|
|
11
14
|
/**
|
|
15
|
+
* An effectful partial transformation.
|
|
16
|
+
*
|
|
17
|
+
* A successful `Some` contains a match, a successful `None` means the input did
|
|
18
|
+
* not match, and an Effect failure remains in the `E` channel. Required
|
|
19
|
+
* services remain in `R`.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* ## Why
|
|
23
|
+
* `Guard` models non-match as successful `None`, keeping ordinary dispatch separate from typed failure, defects, and interruption in Effect's Cause.
|
|
24
|
+
*
|
|
25
|
+
* ## Ownership and lifetime
|
|
26
|
+
* A Guard acquires no resources by itself; each invocation has the lifetime and service requirements of the returned Effect.
|
|
27
|
+
*
|
|
28
|
+
* See [Effect Option](https://effect.website/docs/data-types/option/) and [Effect error management](https://effect.website/docs/v4/error-management/expected-errors/).
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import type { Guard } from "@typed/guard"
|
|
33
|
+
* import { Effect, Option } from "effect"
|
|
34
|
+
* const string: Guard<unknown, string> = (input) => Effect.succeed(typeof input === "string" ? Option.some(input) : Option.none())
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @category Guard contracts
|
|
12
38
|
* @since 1.0.0
|
|
13
39
|
*/
|
|
14
40
|
export type Guard<in I, out O, out E = never, out R = never> = (input: I) => Effect.Effect<Option.Option<O>, E, R>;
|
|
@@ -17,37 +43,144 @@ export type Guard<in I, out O, out E = never, out R = never> = (input: I) => Eff
|
|
|
17
43
|
*/
|
|
18
44
|
export declare namespace Guard {
|
|
19
45
|
/**
|
|
46
|
+
* Extracts the accepted input type from a Guard or Guard adapter.
|
|
47
|
+
* @remarks
|
|
48
|
+
* ## Why
|
|
49
|
+
* The extractor keeps generic APIs aligned with the exact input contract without repeating inference logic.
|
|
50
|
+
* ## Ownership and lifetime
|
|
51
|
+
* This compile-time type acquires no resources and has no runtime lifetime.
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import type { Guard } from "@typed/guard"
|
|
55
|
+
* type Input = Guard.Input<Guard<string, number>>
|
|
56
|
+
* ```
|
|
57
|
+
* @category Type utilities
|
|
20
58
|
* @since 1.0.0
|
|
21
59
|
*/
|
|
22
60
|
type Input<T> = [T] extends [Guard<infer I, infer _R, infer _E, infer _O>] ? I : [T] extends [AsGuard<infer I, infer _R, infer _E, infer _O>] ? I : never;
|
|
23
61
|
/**
|
|
62
|
+
* Extracts the Effect service requirements from a Guard or Guard adapter.
|
|
63
|
+
* @remarks
|
|
64
|
+
* ## Why
|
|
65
|
+
* Service extraction makes environment composition visible in combinator signatures.
|
|
66
|
+
* ## Ownership and lifetime
|
|
67
|
+
* This compile-time type acquires no resources; service lifetime is governed by the resulting Effect or Layer.
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* import type { Guard } from "@typed/guard"
|
|
71
|
+
* type Services = Guard.Services<Guard<string, number, never, { readonly Db: unique symbol }>>
|
|
72
|
+
* ```
|
|
73
|
+
* @category Type utilities
|
|
24
74
|
* @since 1.0.0
|
|
25
75
|
*/
|
|
26
76
|
type Services<T> = [T] extends [Guard<infer _I, infer _O, infer _E, infer R>] ? R : [T] extends [AsGuard<infer _I, infer _O, infer _E, infer R>] ? R : never;
|
|
27
77
|
/**
|
|
78
|
+
* Extracts the typed error channel from a Guard or Guard adapter.
|
|
79
|
+
* @remarks
|
|
80
|
+
* ## Why
|
|
81
|
+
* Typed failure remains distinct from `None`, defects, and interruption throughout composition.
|
|
82
|
+
* ## Ownership and lifetime
|
|
83
|
+
* This compile-time type acquires no resources and has no runtime lifetime.
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import type { Guard } from "@typed/guard"
|
|
87
|
+
* type Error = Guard.Error<Guard<string, number, "Invalid">>
|
|
88
|
+
* ```
|
|
89
|
+
* @category Type utilities
|
|
28
90
|
* @since 1.0.0
|
|
29
91
|
*/
|
|
30
92
|
type Error<T> = [T] extends [Guard<infer _I, infer _O, infer E, infer _R>] ? E : [T] extends [AsGuard<infer _I, infer _O, infer E, infer _R>] ? E : never;
|
|
31
93
|
/**
|
|
94
|
+
* Extracts the matched output type from a Guard or Guard adapter.
|
|
95
|
+
* @remarks
|
|
96
|
+
* ## Why
|
|
97
|
+
* The extractor lets record and dispatch combinators derive their output without duplicating conditional types.
|
|
98
|
+
* ## Ownership and lifetime
|
|
99
|
+
* This compile-time type acquires no resources and has no runtime lifetime.
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* import type { Guard } from "@typed/guard"
|
|
103
|
+
* type Output = Guard.Output<Guard<string, number>>
|
|
104
|
+
* ```
|
|
105
|
+
* @category Type utilities
|
|
32
106
|
* @since 1.0.0
|
|
33
107
|
*/
|
|
34
108
|
type Output<T> = [T] extends [Guard<infer _I, infer O, infer _E, infer _R>] ? O : [T] extends [AsGuard<infer _I, infer O, infer _E, infer _R>] ? O : never;
|
|
35
109
|
}
|
|
36
110
|
/**
|
|
111
|
+
* An object that supplies a Guard through an own callable `asGuard` property.
|
|
112
|
+
* Use an instance field rather than a prototype method.
|
|
113
|
+
*
|
|
114
|
+
* @remarks
|
|
115
|
+
* ## Why
|
|
116
|
+
* An explicit adapter protocol lets domain objects participate in Guard composition without inheritance or wrapper allocation.
|
|
117
|
+
*
|
|
118
|
+
* ## Ownership and lifetime
|
|
119
|
+
* The adapter acquires no resources; the returned Guard owns no lifetime beyond each returned Effect.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```ts
|
|
123
|
+
* import type { AsGuard, Guard } from "@typed/guard"
|
|
124
|
+
* import { Effect } from "effect"
|
|
125
|
+
* const adapter: AsGuard<string, string> = { asGuard: () => ((input) => Effect.succeedSome(input)) as Guard<string, string> }
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @category Guard contracts
|
|
37
129
|
* @since 1.0.0
|
|
38
130
|
*/
|
|
39
131
|
export interface AsGuard<in I, out O, out E = never, out R = never> {
|
|
132
|
+
/**
|
|
133
|
+
* Returns the Guard represented by this adapter.
|
|
134
|
+
* @remarks
|
|
135
|
+
* ## Why
|
|
136
|
+
* Requiring an own callable property avoids ambiguous prototype behavior when adapters cross object boundaries.
|
|
137
|
+
* ## Ownership and lifetime
|
|
138
|
+
* Calling this property acquires no resources; the returned Guard follows its own Effect lifetime.
|
|
139
|
+
* @category Guard contracts
|
|
140
|
+
* @since 1.0.0
|
|
141
|
+
*/
|
|
40
142
|
readonly asGuard: () => Guard<I, O, E, R>;
|
|
41
143
|
}
|
|
42
144
|
/**
|
|
145
|
+
* A Guard or an object that supplies one. Guard combinators accept either form.
|
|
146
|
+
*
|
|
147
|
+
* @remarks
|
|
148
|
+
* ## Why
|
|
149
|
+
* A single input contract lets every combinator accept direct functions and domain adapters consistently.
|
|
150
|
+
*
|
|
151
|
+
* ## Ownership and lifetime
|
|
152
|
+
* This union acquires no resources; normalization does not extend the lifetime of either alternative.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* import type { GuardInput } from "@typed/guard"
|
|
157
|
+
* import { liftPredicate } from "@typed/guard"
|
|
158
|
+
* const input: GuardInput<unknown, string> = liftPredicate((value: unknown): value is string => typeof value === "string")
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @category Guard contracts
|
|
43
162
|
* @since 1.0.0
|
|
44
163
|
*/
|
|
45
164
|
export type GuardInput<I, O, E = never, R = never> = Guard<I, O, E, R> | AsGuard<I, O, E, R>;
|
|
165
|
+
type RecordOutputConstraint<O> = O extends object ? O extends ReadonlyArray<unknown> ? never : unknown : never;
|
|
46
166
|
/**
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
167
|
+
* Runs `output` only when `input` matches. `None` short-circuits successfully,
|
|
168
|
+
* while failures and service requirements are preserved from both Guards.
|
|
169
|
+
*
|
|
170
|
+
* @remarks
|
|
171
|
+
* ## Why
|
|
172
|
+
* Sequential Guard composition must preserve ordinary non-match while unioning the typed error and service channels of both stages.
|
|
173
|
+
*
|
|
174
|
+
* ## Ownership and lifetime
|
|
175
|
+
* Construction acquires no resources; each invocation runs the first Effect and only starts the second after `Some`.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* import { liftPredicate, pipe } from "@typed/guard"
|
|
180
|
+
* const nonEmpty = pipe(liftPredicate((u: unknown): u is string => typeof u === "string"), liftPredicate((s) => s.length > 0))
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* @category Sequential composition
|
|
51
184
|
* @since 1.0.0
|
|
52
185
|
*/
|
|
53
186
|
export declare const pipe: {
|
|
@@ -55,6 +188,19 @@ export declare const pipe: {
|
|
|
55
188
|
<I, O, E, R, B, E2, R2>(input: GuardInput<I, O, E, R>, output: GuardInput<O, B, E2, R2>): Guard<I, B, E | E2, R | R2>;
|
|
56
189
|
};
|
|
57
190
|
/**
|
|
191
|
+
* Maps matched output with an Effect while preserving `None`.
|
|
192
|
+
* @remarks
|
|
193
|
+
* ## Why
|
|
194
|
+
* Effectful mapping can add typed errors and services without changing non-match into failure.
|
|
195
|
+
* ## Ownership and lifetime
|
|
196
|
+
* Construction acquires no resources; the mapping Effect starts only after the source Guard produces `Some`.
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* import { liftPredicate, mapEffect } from "@typed/guard"
|
|
200
|
+
* import { Effect } from "effect"
|
|
201
|
+
* const length = mapEffect(liftPredicate((u: unknown): u is string => typeof u === "string"), (s) => Effect.succeed(s.length))
|
|
202
|
+
* ```
|
|
203
|
+
* @category Value transformations
|
|
58
204
|
* @since 1.0.0
|
|
59
205
|
*/
|
|
60
206
|
export declare const mapEffect: {
|
|
@@ -62,6 +208,18 @@ export declare const mapEffect: {
|
|
|
62
208
|
<I, O, E, R, B, E2, R2>(guard: GuardInput<I, O, E, R>, f: (o: O) => Effect.Effect<B, E2, R2>): Guard<I, B, E | E2, R | R2>;
|
|
63
209
|
};
|
|
64
210
|
/**
|
|
211
|
+
* Maps matched output synchronously while preserving non-match and Effect channels.
|
|
212
|
+
* @remarks
|
|
213
|
+
* ## Why
|
|
214
|
+
* Pure output adaptation should not add errors or services and should never run for `None`.
|
|
215
|
+
* ## Ownership and lifetime
|
|
216
|
+
* Construction acquires no resources; the callback runs once for each `Some` during Effect execution.
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* import { liftPredicate, map } from "@typed/guard"
|
|
220
|
+
* const length = map(liftPredicate((u: unknown): u is string => typeof u === "string"), (s) => s.length)
|
|
221
|
+
* ```
|
|
222
|
+
* @category Value transformations
|
|
65
223
|
* @since 1.0.0
|
|
66
224
|
*/
|
|
67
225
|
export declare const map: {
|
|
@@ -69,13 +227,40 @@ export declare const map: {
|
|
|
69
227
|
<I, O, E, R, B>(guard: GuardInput<I, O, E, R>, f: (o: O) => B): Guard<I, B, E, R>;
|
|
70
228
|
};
|
|
71
229
|
/**
|
|
230
|
+
* Runs a synchronous or Effectful observation for each matched value and returns the value unchanged.
|
|
231
|
+
* @remarks
|
|
232
|
+
* ## Why
|
|
233
|
+
* Observation composes without changing output, while Effect callbacks correctly contribute their errors and services.
|
|
234
|
+
* ## Ownership and lifetime
|
|
235
|
+
* Construction acquires no resources; callback lifetime is bounded by each matching Guard invocation.
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* import { liftPredicate, tap } from "@typed/guard"
|
|
239
|
+
* const observed = tap(liftPredicate((u: unknown): u is string => typeof u === "string"), console.log)
|
|
240
|
+
* ```
|
|
241
|
+
* @category Effectful observation
|
|
72
242
|
* @since 1.0.0
|
|
73
243
|
*/
|
|
74
244
|
export declare const tap: {
|
|
75
|
-
<O
|
|
76
|
-
<
|
|
245
|
+
<O>(f: (o: O) => void): <I, R, E>(guard: GuardInput<I, O, E, R>) => Guard<I, O, E, R>;
|
|
246
|
+
<O, B, E2, R2>(f: (o: O) => Effect.Effect<B, E2, R2>): <I, R, E>(guard: GuardInput<I, O, E, R>) => Guard<I, O, E | E2, R | R2>;
|
|
247
|
+
<I, O, E, R>(guard: GuardInput<I, O, E, R>, f: (o: O) => void): Guard<I, O, E, R>;
|
|
248
|
+
<I, O, E, R, B, E2, R2>(guard: GuardInput<I, O, E, R>, f: (o: O) => Effect.Effect<B, E2, R2>): Guard<I, O, E | E2, R | R2>;
|
|
77
249
|
};
|
|
78
250
|
/**
|
|
251
|
+
* Refines and maps a matched value with an Option-returning function.
|
|
252
|
+
* @remarks
|
|
253
|
+
* ## Why
|
|
254
|
+
* `Option.none` provides a second ordinary non-match stage without introducing typed failure.
|
|
255
|
+
* ## Ownership and lifetime
|
|
256
|
+
* This combinator acquires no resources; the callback runs only for source matches.
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* import { filterMap, liftPredicate } from "@typed/guard"
|
|
260
|
+
* import { Option } from "effect"
|
|
261
|
+
* const parsed = filterMap(liftPredicate((u: unknown): u is string => typeof u === "string"), (s) => s ? Option.some(Number(s)) : Option.none())
|
|
262
|
+
* ```
|
|
263
|
+
* @category Input selection
|
|
79
264
|
* @since 1.0.0
|
|
80
265
|
*/
|
|
81
266
|
export declare const filterMap: {
|
|
@@ -83,24 +268,79 @@ export declare const filterMap: {
|
|
|
83
268
|
<I, O, E, R, B>(guard: GuardInput<I, O, E, R>, f: (o: O) => Option.Option<B>): Guard<I, B, E, R>;
|
|
84
269
|
};
|
|
85
270
|
/**
|
|
271
|
+
* Keeps matched values that satisfy a predicate or refinement.
|
|
272
|
+
* @remarks
|
|
273
|
+
* ## Why
|
|
274
|
+
* Predicate failure remains successful `None`, preserving Guard dispatch semantics and type refinement.
|
|
275
|
+
* ## Ownership and lifetime
|
|
276
|
+
* This combinator acquires no resources; the predicate runs only for source matches.
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* import { filter, liftPredicate } from "@typed/guard"
|
|
280
|
+
* const positive = filter(liftPredicate((u: unknown): u is number => typeof u === "number"), (n) => n > 0)
|
|
281
|
+
* ```
|
|
282
|
+
* @category Input selection
|
|
86
283
|
* @since 1.0.0
|
|
87
284
|
*/
|
|
88
285
|
export declare const filter: {
|
|
89
|
-
<O, O2 extends O>(predicate: (o: O) => o is O2): <I, R, E>(guard: GuardInput<I, O, E, R>) => Guard<I,
|
|
286
|
+
<O, O2 extends O>(predicate: (o: O) => o is O2): <I, R, E>(guard: GuardInput<I, O, E, R>) => Guard<I, O2, E, R>;
|
|
90
287
|
<O>(predicate: (o: O) => boolean): <I, R, E>(guard: GuardInput<I, O, E, R>) => Guard<I, O, E, R>;
|
|
91
|
-
<I, O, E, R, O2 extends O>(guard: GuardInput<I, O, E, R>, predicate: (o: O) => o is O2): Guard<I,
|
|
288
|
+
<I, O, E, R, O2 extends O>(guard: GuardInput<I, O, E, R>, predicate: (o: O) => o is O2): Guard<I, O2, E, R>;
|
|
92
289
|
<I, O, E, R>(guard: GuardInput<I, O, E, R>, predicate: (o: O) => boolean): Guard<I, O, E, R>;
|
|
93
290
|
};
|
|
94
291
|
/**
|
|
292
|
+
* Runs candidates sequentially and returns the first match tagged with its key.
|
|
293
|
+
* Candidates are snapshotted from own enumerable keys when `any` is called.
|
|
294
|
+
* ECMAScript own-key order applies: integer-index strings, other strings, then
|
|
295
|
+
* symbols.
|
|
296
|
+
*
|
|
297
|
+
* @remarks
|
|
298
|
+
* ## Why
|
|
299
|
+
* Ordered first-match dispatch turns independently composable Guards into a deterministic tagged union without treating `None` as failure.
|
|
300
|
+
*
|
|
301
|
+
* ## Ownership and lifetime
|
|
302
|
+
* Construction snapshots own enumerable entries and acquires no resources; each run executes candidates sequentially until the first `Some`.
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* import { any, liftPredicate } from "@typed/guard"
|
|
307
|
+
* const classify = any({ text: liftPredicate((u: unknown): u is string => typeof u === "string") })
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* @category Alternative selection
|
|
95
311
|
* @since 1.0.0
|
|
96
312
|
*/
|
|
97
313
|
export declare function any<const GS extends Readonly<Record<string, GuardInput<any, any, any, any>>>>(guards: GS): Guard<AnyInput<GS>, AnyOutput<GS>, Guard.Error<GS[keyof GS]>, Guard.Services<GS[keyof GS]>>;
|
|
98
314
|
/**
|
|
315
|
+
* Computes the intersection of inputs accepted by an `any` Guard record.
|
|
316
|
+
* @remarks
|
|
317
|
+
* ## Why
|
|
318
|
+
* Every candidate receives the same runtime value, so the input must satisfy all candidate input contracts.
|
|
319
|
+
* ## Ownership and lifetime
|
|
320
|
+
* This compile-time type acquires no resources and has no runtime lifetime.
|
|
321
|
+
* @example
|
|
322
|
+
* ```ts
|
|
323
|
+
* import type { AnyInput, Guard } from "@typed/guard"
|
|
324
|
+
* type Input = AnyInput<{ text: Guard<unknown, string>; count: Guard<unknown, number> }>
|
|
325
|
+
* ```
|
|
326
|
+
* @category Type utilities
|
|
99
327
|
* @since 1.0.0
|
|
100
328
|
*/
|
|
101
329
|
export type AnyInput<GS extends Readonly<Record<string, GuardInput<any, any, any, any>>>> = UnionToIntersection<Guard.Input<GS[keyof GS]>>;
|
|
102
330
|
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;
|
|
103
331
|
/**
|
|
332
|
+
* Builds the tagged output union produced by `any`.
|
|
333
|
+
* @remarks
|
|
334
|
+
* ## Why
|
|
335
|
+
* Preserving each record key in `_tag` lets downstream code narrow the winning Guard's value exhaustively.
|
|
336
|
+
* ## Ownership and lifetime
|
|
337
|
+
* This compile-time type acquires no resources and has no runtime lifetime.
|
|
338
|
+
* @example
|
|
339
|
+
* ```ts
|
|
340
|
+
* import type { AnyOutput, Guard } from "@typed/guard"
|
|
341
|
+
* type Output = AnyOutput<{ text: Guard<unknown, string>; count: Guard<unknown, number> }>
|
|
342
|
+
* ```
|
|
343
|
+
* @category Type utilities
|
|
104
344
|
* @since 1.0.0
|
|
105
345
|
*/
|
|
106
346
|
export type AnyOutput<GS extends Readonly<Record<string, GuardInput<any, any, any, any>>>> = [
|
|
@@ -112,11 +352,44 @@ export type AnyOutput<GS extends Readonly<Record<string, GuardInput<any, any, an
|
|
|
112
352
|
}[keyof GS]
|
|
113
353
|
] extends [infer R] ? R : never;
|
|
114
354
|
/**
|
|
355
|
+
* Builds a Guard from a predicate or refinement. The predicate is evaluated
|
|
356
|
+
* only when the returned Effect runs. A thrown exception becomes an Effect
|
|
357
|
+
* defect; use an effectful Guard when failure belongs in the typed error channel.
|
|
358
|
+
*
|
|
359
|
+
* @remarks
|
|
360
|
+
* ## Why
|
|
361
|
+
* Predicate lifting is the bridge from synchronous refinements into deferred Guard composition while preserving the `None` versus failure distinction.
|
|
362
|
+
*
|
|
363
|
+
* ## Ownership and lifetime
|
|
364
|
+
* Construction acquires no resources; the predicate runs once per invocation when the returned Effect executes.
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```ts
|
|
368
|
+
* import { liftPredicate } from "@typed/guard"
|
|
369
|
+
* const string = liftPredicate((value: unknown): value is string => typeof value === "string")
|
|
370
|
+
* ```
|
|
371
|
+
*
|
|
372
|
+
* @category Input selection
|
|
115
373
|
* @since 1.0.0
|
|
116
374
|
*/
|
|
117
375
|
export declare function liftPredicate<A, B extends A>(predicate: Predicate.Refinement<A, B>): Guard<A, B>;
|
|
118
376
|
export declare function liftPredicate<A>(predicate: Predicate.Predicate<A>): Guard<A, A>;
|
|
119
377
|
/**
|
|
378
|
+
* Recovers from the complete Effect Cause and lifts the recovery result into `Some`.
|
|
379
|
+
* @remarks
|
|
380
|
+
* ## Why
|
|
381
|
+
* Cause-aware recovery can deliberately handle typed failures, defects, and interruption; `None` remains an unrecovered non-match.
|
|
382
|
+
* ## Ownership and lifetime
|
|
383
|
+
* Construction acquires no resources; recovery starts only when the source Effect fails and follows that invocation's lifetime.
|
|
384
|
+
* @example
|
|
385
|
+
* ```ts
|
|
386
|
+
* import { catchCause } from "@typed/guard"
|
|
387
|
+
* import type { Guard } from "@typed/guard"
|
|
388
|
+
* import { Effect } from "effect"
|
|
389
|
+
* const source: Guard<string, string, string> = (input) => input ? Effect.succeedSome(input) : Effect.fail("empty")
|
|
390
|
+
* const recovered = catchCause(source, () => Effect.succeed("fallback"))
|
|
391
|
+
* ```
|
|
392
|
+
* @category Error recovery
|
|
120
393
|
* @since 1.0.0
|
|
121
394
|
*/
|
|
122
395
|
export declare const catchCause: {
|
|
@@ -124,6 +397,21 @@ export declare const catchCause: {
|
|
|
124
397
|
<I, O, E, R, O2, E2, R2>(guard: GuardInput<I, O, E, R>, f: (e: Cause.Cause<E>) => Effect.Effect<O2, E2, R2>): Guard<I, O | O2, E2, R | R2>;
|
|
125
398
|
};
|
|
126
399
|
/**
|
|
400
|
+
* Recovers typed failures and lifts the recovery result into `Some`.
|
|
401
|
+
* @remarks
|
|
402
|
+
* ## Why
|
|
403
|
+
* Typed recovery leaves defects and interruption untouched and does not confuse successful `None` with failure. The exported `catch` name is an alias of this declaration.
|
|
404
|
+
* ## Ownership and lifetime
|
|
405
|
+
* Construction acquires no resources; recovery starts only for typed failure during the source invocation.
|
|
406
|
+
* @example
|
|
407
|
+
* ```ts
|
|
408
|
+
* import { catchAll } from "@typed/guard"
|
|
409
|
+
* import type { Guard } from "@typed/guard"
|
|
410
|
+
* import { Effect } from "effect"
|
|
411
|
+
* const source: Guard<string, string, string> = (input) => input ? Effect.succeedSome(input) : Effect.fail("empty")
|
|
412
|
+
* const recovered = catchAll(source, (error) => Effect.succeed(error.length))
|
|
413
|
+
* ```
|
|
414
|
+
* @category Error recovery
|
|
127
415
|
* @since 1.0.0
|
|
128
416
|
*/
|
|
129
417
|
export declare const catchAll: {
|
|
@@ -132,97 +420,254 @@ export declare const catchAll: {
|
|
|
132
420
|
};
|
|
133
421
|
export { catchAll as catch };
|
|
134
422
|
/**
|
|
423
|
+
* Recovers selected tagged typed failures and leaves unmatched tags in the error channel.
|
|
424
|
+
* @remarks
|
|
425
|
+
* ## Why
|
|
426
|
+
* Tag-specific recovery preserves type-safe residual errors while lifting recovered output into `Some`; `None`, defects, and interruption are unchanged.
|
|
427
|
+
* ## Ownership and lifetime
|
|
428
|
+
* Construction acquires no resources; the handler runs only for matching tagged failures during an invocation.
|
|
429
|
+
* @example
|
|
430
|
+
* ```ts
|
|
431
|
+
* import { catchTag } from "@typed/guard"
|
|
432
|
+
* import type { Guard } from "@typed/guard"
|
|
433
|
+
* import { Effect } from "effect"
|
|
434
|
+
* type NotFound = { readonly _tag: "NotFound" }
|
|
435
|
+
* const source: Guard<string, string, NotFound> = (input) => input ? Effect.succeedSome(input) : Effect.fail({ _tag: "NotFound" })
|
|
436
|
+
* const recovered = catchTag(source, "NotFound", () => Effect.succeed("fallback"))
|
|
437
|
+
* ```
|
|
438
|
+
* @category Error recovery
|
|
135
439
|
* @since 1.0.0
|
|
136
440
|
*/
|
|
137
441
|
export declare const catchTag: {
|
|
138
|
-
<E, K extends E extends
|
|
139
|
-
|
|
140
|
-
} ? E["_tag"] : never, O2, E2, R2>(tag: K, f: (e: Extract<E, {
|
|
141
|
-
_tag: K;
|
|
142
|
-
}>) => Effect.Effect<O2, E2, R2>): <I, O, R>(guard: GuardInput<I, O, E, R>) => Guard<I, O | O2, E2 | Exclude<E, {
|
|
143
|
-
_tag: K;
|
|
144
|
-
}>, R | R2>;
|
|
145
|
-
<I, O, E, R, K extends E extends {
|
|
146
|
-
_tag: string;
|
|
147
|
-
} ? E["_tag"] : never, O2, E2, R2>(guard: GuardInput<I, O, E, R>, tag: K, f: (e: Extract<E, {
|
|
148
|
-
_tag: K;
|
|
149
|
-
}>) => Effect.Effect<O2, E2, R2>): Guard<I, O | O2, E2 | Exclude<E, {
|
|
150
|
-
_tag: K;
|
|
151
|
-
}>, R | R2>;
|
|
442
|
+
<const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, E, O2, E2, R2>(tag: K, f: (e: ExtractTag<NoInfer<E>, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<O2, E2, R2>): <I, O, R>(guard: GuardInput<I, O, E, R>) => Guard<I, O | O2, E2 | ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>, R | R2>;
|
|
443
|
+
<I, O, E, R, const K extends Tags<E> | Arr.NonEmptyReadonlyArray<Tags<E>>, O2, E2, R2>(guard: GuardInput<I, O, E, R>, tag: K, f: (e: ExtractTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>) => Effect.Effect<O2, E2, R2>): Guard<I, O | O2, E2 | ExcludeTag<E, K extends Arr.NonEmptyReadonlyArray<string> ? K[number] : K>, R | R2>;
|
|
152
444
|
};
|
|
153
445
|
/**
|
|
446
|
+
* Provides a Context or Layer to a Guard's Effect.
|
|
447
|
+
* @remarks
|
|
448
|
+
* ## Why
|
|
449
|
+
* Provision removes supplied services from `R`; Layers may also contribute acquisition errors and their own requirements exactly as Effect does.
|
|
450
|
+
* ## Ownership and lifetime
|
|
451
|
+
* A Context acquires no resources here. Layer resources are acquired and released according to the Effect Scope that runs the Guard.
|
|
452
|
+
* @example
|
|
453
|
+
* ```ts
|
|
454
|
+
* import { provide } from "@typed/guard"
|
|
455
|
+
* import type { Guard } from "@typed/guard"
|
|
456
|
+
* import { Context, Effect, Option } from "effect"
|
|
457
|
+
* const Flag = Context.Service<{ readonly enabled: boolean }>("Flag")
|
|
458
|
+
* const requiresFlag: Guard<boolean, boolean, never, Context.Service.Identifier<typeof Flag>> = (input) => Effect.map(Effect.service(Flag), ({ enabled }) => enabled && input ? Option.some(input) : Option.none())
|
|
459
|
+
* const guard = provide(requiresFlag, Context.make(Flag, { enabled: true }))
|
|
460
|
+
* ```
|
|
461
|
+
* See [Effect services and Layers](https://effect.website/docs/requirements-management/layers/).
|
|
462
|
+
* @category Services
|
|
154
463
|
* @since 1.0.0
|
|
155
464
|
*/
|
|
156
465
|
export declare const provide: {
|
|
157
|
-
<R2>(provided:
|
|
466
|
+
<R2>(provided: Context.Context<R2>): <I, O, E, R>(guard: GuardInput<I, O, E, R>) => Guard<I, O, E, Exclude<R, R2>>;
|
|
158
467
|
<R2, E2, R3>(provided: Layer.Layer<R2, E2, R3>): <I, O, E, R>(guard: GuardInput<I, O, E, R>) => Guard<I, O, E | E2, Exclude<R, R2> | R3>;
|
|
159
|
-
<I, O, E, R, R2>(guard: GuardInput<I, O, E, R>, provided:
|
|
468
|
+
<I, O, E, R, R2>(guard: GuardInput<I, O, E, R>, provided: Context.Context<R2>): Guard<I, O, E, Exclude<R, R2>>;
|
|
160
469
|
<I, O, E, R, R2, E2, R3>(guard: GuardInput<I, O, E, R>, provided: Layer.Layer<R2, E2, R3>): Guard<I, O, E | E2, Exclude<R, R2> | R3>;
|
|
161
470
|
};
|
|
162
471
|
/**
|
|
472
|
+
* Provides one concrete service to a Guard.
|
|
473
|
+
* @remarks
|
|
474
|
+
* ## Why
|
|
475
|
+
* Targeted service provision removes only the selected identifier from the Guard environment.
|
|
476
|
+
* ## Ownership and lifetime
|
|
477
|
+
* This combinator acquires no resources and reuses the supplied service for each invocation.
|
|
478
|
+
* @example
|
|
479
|
+
* ```ts
|
|
480
|
+
* import { provideService } from "@typed/guard"
|
|
481
|
+
* import type { Guard } from "@typed/guard"
|
|
482
|
+
* import { Context, Effect, Option } from "effect"
|
|
483
|
+
* const Flag = Context.Service<{ readonly enabled: boolean }>("Flag")
|
|
484
|
+
* const requiresFlag: Guard<boolean, boolean, never, Context.Service.Identifier<typeof Flag>> = (input) => Effect.map(Effect.service(Flag), ({ enabled }) => enabled && input ? Option.some(input) : Option.none())
|
|
485
|
+
* const guard = provideService(requiresFlag, Flag, { enabled: true })
|
|
486
|
+
* ```
|
|
487
|
+
* @category Services
|
|
163
488
|
* @since 1.0.0
|
|
164
489
|
*/
|
|
165
490
|
export declare const provideService: {
|
|
166
|
-
<Id, S>(tag:
|
|
167
|
-
<I, O, E, R, Id, S>(guard: GuardInput<I, O, E, R>, tag:
|
|
491
|
+
<Id, S>(tag: Context.Service<Id, S>, service: S): <I, O, E, R>(guard: GuardInput<I, O, E, R>) => Guard<I, O, E, Exclude<R, Id>>;
|
|
492
|
+
<I, O, E, R, Id, S>(guard: GuardInput<I, O, E, R>, tag: Context.Service<Id, S>, service: S): Guard<I, O, E, Exclude<R, Id>>;
|
|
168
493
|
};
|
|
169
494
|
/**
|
|
495
|
+
* Provides a service produced by an Effect to a Guard.
|
|
496
|
+
* @remarks
|
|
497
|
+
* ## Why
|
|
498
|
+
* Effectful provision makes acquisition errors and required services explicit in the composed Guard channels.
|
|
499
|
+
* ## Ownership and lifetime
|
|
500
|
+
* The service Effect runs for each Guard invocation and is interrupted with that invocation; scoped resources follow the surrounding Scope.
|
|
501
|
+
* @example
|
|
502
|
+
* ```ts
|
|
503
|
+
* import { provideServiceEffect } from "@typed/guard"
|
|
504
|
+
* import type { Guard } from "@typed/guard"
|
|
505
|
+
* import { Context, Effect, Option } from "effect"
|
|
506
|
+
* const Flag = Context.Service<{ readonly enabled: boolean }>("Flag")
|
|
507
|
+
* const requiresFlag: Guard<boolean, boolean, never, Context.Service.Identifier<typeof Flag>> = (input) => Effect.map(Effect.service(Flag), ({ enabled }) => enabled && input ? Option.some(input) : Option.none())
|
|
508
|
+
* const guard = provideServiceEffect(requiresFlag, Flag, Effect.succeed({ enabled: true }))
|
|
509
|
+
* ```
|
|
510
|
+
* @category Services
|
|
170
511
|
* @since 1.0.0
|
|
171
512
|
*/
|
|
172
513
|
export declare const provideServiceEffect: {
|
|
173
|
-
<Id, S, E2, R2>(tag:
|
|
174
|
-
<I, O, E, R, Id, S, E2, R2>(guard: GuardInput<I, O, E, R>, tag:
|
|
514
|
+
<Id, S, E2, R2>(tag: Context.Service<Id, S>, service: Effect.Effect<S, E2, R2>): <I, O, E, R>(guard: GuardInput<I, O, E, R>) => Guard<I, O, E | E2, Exclude<R, Id> | R2>;
|
|
515
|
+
<I, O, E, R, Id, S, E2, R2>(guard: GuardInput<I, O, E, R>, tag: Context.Service<Id, S>, service: Effect.Effect<S, E2, R2>): Guard<I, O, E | E2, Exclude<R, Id> | R2>;
|
|
175
516
|
};
|
|
176
517
|
/**
|
|
518
|
+
* Creates a Guard that decodes a schema's Encoded input to its Type.
|
|
519
|
+
* @remarks
|
|
520
|
+
* ## Why
|
|
521
|
+
* Schema decoding reports all issues, ignores excess properties, retains `SchemaError` in the typed channel, and carries decoding services in `R`.
|
|
522
|
+
* ## Ownership and lifetime
|
|
523
|
+
* Construction acquires no resources; schema services and any scoped work follow each returned Effect invocation.
|
|
524
|
+
* @example
|
|
525
|
+
* ```ts
|
|
526
|
+
* import { fromSchemaDecode } from "@typed/guard"
|
|
527
|
+
* import { Schema } from "effect"
|
|
528
|
+
* const number = fromSchemaDecode(Schema.NumberFromString)
|
|
529
|
+
* ```
|
|
530
|
+
* See [Effect Schema transformations](https://effect.website/docs/schema/transformations/).
|
|
531
|
+
* @category Schema decoding and encoding
|
|
177
532
|
* @since 1.0.0
|
|
178
533
|
*/
|
|
179
534
|
export declare function fromSchemaDecode<S extends Schema.Top>(schema: S): Guard<S["Encoded"], S["Type"], Schema.SchemaError, S["DecodingServices"]>;
|
|
180
535
|
/**
|
|
536
|
+
* Creates a Guard that encodes a schema's Type to its Encoded representation.
|
|
537
|
+
* @remarks
|
|
538
|
+
* ## Why
|
|
539
|
+
* Schema encoding is the reverse direction of decoding and keeps encoding services and `SchemaError` visible in the Guard type.
|
|
540
|
+
* ## Ownership and lifetime
|
|
541
|
+
* Construction acquires no resources; schema services and any scoped work follow each returned Effect invocation.
|
|
542
|
+
* @example
|
|
543
|
+
* ```ts
|
|
544
|
+
* import { fromSchemaEncode } from "@typed/guard"
|
|
545
|
+
* import { Schema } from "effect"
|
|
546
|
+
* const encoded = fromSchemaEncode(Schema.NumberFromString)
|
|
547
|
+
* ```
|
|
548
|
+
* @category Schema decoding and encoding
|
|
181
549
|
* @since 1.0.0
|
|
182
550
|
*/
|
|
183
551
|
export declare function fromSchemaEncode<S extends Schema.Top>(schema: S): Guard<S["Type"], S["Encoded"], Schema.SchemaError, S["EncodingServices"]>;
|
|
184
552
|
/**
|
|
553
|
+
* Decodes each matched encoded value through an Effect Schema.
|
|
554
|
+
* @remarks
|
|
555
|
+
* ## Why
|
|
556
|
+
* The composed Guard preserves source non-match and errors while adding schema failures and decoding service requirements.
|
|
557
|
+
* ## Ownership and lifetime
|
|
558
|
+
* Construction acquires no resources; decoding starts only for `Some` and follows that invocation's lifetime.
|
|
559
|
+
* @example
|
|
560
|
+
* ```ts
|
|
561
|
+
* import { decode, liftPredicate } from "@typed/guard"
|
|
562
|
+
* import { Schema } from "effect"
|
|
563
|
+
* const number = decode(liftPredicate((u: unknown): u is string => typeof u === "string"), Schema.NumberFromString)
|
|
564
|
+
* ```
|
|
565
|
+
* @category Schema decoding and encoding
|
|
185
566
|
* @since 1.0.0
|
|
186
567
|
*/
|
|
187
568
|
export declare const decode: {
|
|
188
|
-
<S extends Schema.Top>(schema: S): <I, E = never, R = never>(guard: GuardInput<I, S["
|
|
189
|
-
<I,
|
|
569
|
+
<S extends Schema.Top>(schema: S): <I, E = never, R = never>(guard: GuardInput<I, S["Encoded"], E, R>) => Guard<I, S["Type"], Schema.SchemaError | E, R | S["DecodingServices"]>;
|
|
570
|
+
<I, E, R, S extends Schema.Top>(guard: GuardInput<I, S["Encoded"], E, R>, schema: S): Guard<I, S["Type"], Schema.SchemaError | E, R | S["DecodingServices"]>;
|
|
190
571
|
};
|
|
191
572
|
/**
|
|
573
|
+
* Encodes each matched schema Type to its Encoded representation.
|
|
574
|
+
* @remarks
|
|
575
|
+
* ## Why
|
|
576
|
+
* The composed Guard preserves source non-match and errors while adding schema failures and encoding service requirements.
|
|
577
|
+
* ## Ownership and lifetime
|
|
578
|
+
* Construction acquires no resources; encoding starts only for `Some` and follows that invocation's lifetime.
|
|
579
|
+
* @example
|
|
580
|
+
* ```ts
|
|
581
|
+
* import { encode, liftPredicate } from "@typed/guard"
|
|
582
|
+
* import { Schema } from "effect"
|
|
583
|
+
* const text = encode(liftPredicate((u: unknown): u is number => typeof u === "number"), Schema.NumberFromString)
|
|
584
|
+
* ```
|
|
585
|
+
* @category Schema decoding and encoding
|
|
192
586
|
* @since 1.0.0
|
|
193
587
|
*/
|
|
194
588
|
export declare const encode: {
|
|
195
|
-
<S extends Schema.Top>(schema: S): <I, E = never, R = never>(guard: GuardInput<I, S["Type"], E, R>) => Guard<I, S["
|
|
196
|
-
<I,
|
|
589
|
+
<S extends Schema.Top>(schema: S): <I, E = never, R = never>(guard: GuardInput<I, S["Type"], E, R>) => Guard<I, S["Encoded"], Schema.SchemaError | E, R | S["EncodingServices"]>;
|
|
590
|
+
<I, E, R, S extends Schema.Top>(guard: GuardInput<I, S["Type"], E, R>, schema: S): Guard<I, S["Encoded"], Schema.SchemaError | E, R | S["EncodingServices"]>;
|
|
197
591
|
};
|
|
198
592
|
/**
|
|
593
|
+
* Adds a fixed property to every matched record output.
|
|
594
|
+
* @remarks
|
|
595
|
+
* ## Why
|
|
596
|
+
* Record construction does not mutate the input and rejects existing enumerable keys; it returns an unfrozen plain object containing own enumerable string and symbol properties while dropping prototypes and non-enumerables.
|
|
597
|
+
* ## Ownership and lifetime
|
|
598
|
+
* This pure combinator acquires no resources and creates a fresh plain object for every match.
|
|
599
|
+
* @example
|
|
600
|
+
* ```ts
|
|
601
|
+
* import { bindTo, let as letGuard, liftPredicate } from "@typed/guard"
|
|
602
|
+
* const named = letGuard(bindTo(liftPredicate(Boolean), "value"), "kind", "input")
|
|
603
|
+
* ```
|
|
604
|
+
* @category Record construction
|
|
199
605
|
* @since 1.0.0
|
|
200
606
|
*/
|
|
201
607
|
declare const let_: {
|
|
202
|
-
<K extends PropertyKey, B>(key: K, value: B): <
|
|
608
|
+
<K extends PropertyKey, B>(key: K, value: B): <G extends GuardInput<any, any, any, any>>(guard: G & RecordOutputConstraint<NoInfer<Guard.Output<G>>> & (K extends NoInfer<Guard.Output<G> extends infer O ? (O extends unknown ? keyof O : never) : never> ? never : unknown)) => Guard<Guard.Input<G>, Guard.Output<G> & {
|
|
203
609
|
[k in K]: B;
|
|
204
|
-
},
|
|
205
|
-
<
|
|
610
|
+
}, Guard.Error<G>, Guard.Services<G>>;
|
|
611
|
+
<G extends GuardInput<any, any, any, any>, K extends PropertyKey, B>(guard: G & RecordOutputConstraint<NoInfer<Guard.Output<G>>>, key: Exclude<K, NoInfer<Guard.Output<G> extends infer O ? (O extends unknown ? keyof O : never) : never>>, value: B): Guard<Guard.Input<G>, Guard.Output<G> & {
|
|
206
612
|
[k in K]: B;
|
|
207
|
-
},
|
|
613
|
+
}, Guard.Error<G>, Guard.Services<G>>;
|
|
208
614
|
};
|
|
209
615
|
export {
|
|
210
616
|
/**
|
|
617
|
+
* Adds a fixed property to every matched object output. The key must not
|
|
618
|
+
* already exist; use `bindTo` first when the prior output is not an object.
|
|
619
|
+
*
|
|
620
|
+
* This alias shares the canonical documentation and behavior of `let_`.
|
|
621
|
+
*
|
|
211
622
|
* @since 1.0.0
|
|
212
623
|
*/
|
|
213
624
|
let_ as let, };
|
|
214
625
|
/**
|
|
626
|
+
* Adds a readonly `_tag` to every matched object output. The output must not
|
|
627
|
+
* already have an `_tag` property.
|
|
628
|
+
*
|
|
629
|
+
* @remarks
|
|
630
|
+
* ## Why
|
|
631
|
+
* A typed discriminant turns matched record outputs into exhaustively narrowable tagged values while rejecting key collisions.
|
|
632
|
+
*
|
|
633
|
+
* ## Ownership and lifetime
|
|
634
|
+
* This pure combinator acquires no resources and creates a fresh plain object for every match.
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* ```ts
|
|
638
|
+
* import { addTag, bindTo, liftPredicate } from "@typed/guard"
|
|
639
|
+
* const tagged = addTag(bindTo(liftPredicate(Boolean), "value"), "Input")
|
|
640
|
+
* ```
|
|
641
|
+
*
|
|
642
|
+
* @category Record construction
|
|
215
643
|
* @since 1.0.0
|
|
216
644
|
*/
|
|
217
645
|
export declare const addTag: {
|
|
218
|
-
<B>(value: B): <
|
|
646
|
+
<B>(value: B): <G extends GuardInput<any, any, any, any>>(guard: G & RecordOutputConstraint<NoInfer<Guard.Output<G>>> & ("_tag" extends NoInfer<Guard.Output<G> extends infer O ? (O extends unknown ? keyof O : never) : never> ? never : unknown)) => Guard<Guard.Input<G>, Guard.Output<G> & {
|
|
219
647
|
readonly _tag: B;
|
|
220
|
-
},
|
|
221
|
-
<
|
|
648
|
+
}, Guard.Error<G>, Guard.Services<G>>;
|
|
649
|
+
<G extends GuardInput<any, any, any, any>, B>(guard: G & RecordOutputConstraint<NoInfer<Guard.Output<G>>> & ("_tag" extends NoInfer<Guard.Output<G> extends infer O ? (O extends unknown ? keyof O : never) : never> ? never : unknown), value: B): Guard<Guard.Input<G>, Guard.Output<G> & {
|
|
222
650
|
readonly _tag: B;
|
|
223
|
-
},
|
|
651
|
+
}, Guard.Error<G>, Guard.Services<G>>;
|
|
224
652
|
};
|
|
225
653
|
/**
|
|
654
|
+
* Wraps any matched output in a new object under `key`. This is the explicit
|
|
655
|
+
* transition from an arbitrary output to the record-building workflow.
|
|
656
|
+
*
|
|
657
|
+
* @remarks
|
|
658
|
+
* ## Why
|
|
659
|
+
* Explicit wrapping makes arbitrary values safe for record combinators without assuming their runtime shape.
|
|
660
|
+
*
|
|
661
|
+
* ## Ownership and lifetime
|
|
662
|
+
* This pure combinator acquires no resources and creates a fresh plain object for every match.
|
|
663
|
+
*
|
|
664
|
+
* @example
|
|
665
|
+
* ```ts
|
|
666
|
+
* import { bindTo, liftPredicate } from "@typed/guard"
|
|
667
|
+
* const named = bindTo(liftPredicate(Boolean), "value")
|
|
668
|
+
* ```
|
|
669
|
+
*
|
|
670
|
+
* @category Record construction
|
|
226
671
|
* @since 1.0.0
|
|
227
672
|
*/
|
|
228
673
|
export declare const bindTo: {
|
|
@@ -234,14 +679,34 @@ export declare const bindTo: {
|
|
|
234
679
|
}, E, R>;
|
|
235
680
|
};
|
|
236
681
|
/**
|
|
682
|
+
* Runs `f` on a matched object and adds its matched value under a new key. The
|
|
683
|
+
* key must not already exist. Enumerable getters and proxy traps may execute
|
|
684
|
+
* during the object spread.
|
|
685
|
+
*
|
|
686
|
+
* @remarks
|
|
687
|
+
* ## Why
|
|
688
|
+
* Dependent record construction runs the second Guard only after the base matches, preserves `None`, and unions both error and service channels.
|
|
689
|
+
*
|
|
690
|
+
* ## Ownership and lifetime
|
|
691
|
+
* Construction acquires no resources; each successful bind creates a fresh plain object and the dependent Effect follows the invocation lifetime.
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```ts
|
|
695
|
+
* import { bind, bindTo, liftPredicate, map } from "@typed/guard"
|
|
696
|
+
* const base = bindTo(liftPredicate((u: unknown): u is string => typeof u === "string"), "text")
|
|
697
|
+
* const nonEmptyLength = map(liftPredicate((record: { readonly text: string }) => record.text.length > 0), (record) => record.text.length)
|
|
698
|
+
* const sized = bind(base, "length", nonEmptyLength)
|
|
699
|
+
* ```
|
|
700
|
+
*
|
|
701
|
+
* @category Record construction
|
|
237
702
|
* @since 1.0.0
|
|
238
703
|
*/
|
|
239
704
|
export declare const bind: {
|
|
240
|
-
<
|
|
705
|
+
<O extends object, K extends PropertyKey, B, E2, R2>(key: K, f: GuardInput<O, B, E2, R2>): <G extends GuardInput<any, O, any, any>>(guard: G & RecordOutputConstraint<NoInfer<Guard.Output<G>>> & (K extends NoInfer<Guard.Output<G> extends infer A ? (A extends unknown ? keyof A : never) : never> ? never : unknown)) => Guard<Guard.Input<G>, Guard.Output<G> & {
|
|
241
706
|
[k in K]: B;
|
|
242
|
-
},
|
|
243
|
-
<
|
|
707
|
+
}, Guard.Error<G> | E2, Guard.Services<G> | R2>;
|
|
708
|
+
<G extends GuardInput<any, any, any, any>, K extends PropertyKey, B, E2, R2>(guard: G & RecordOutputConstraint<NoInfer<Guard.Output<G>>>, key: Exclude<K, NoInfer<Guard.Output<G> extends infer O ? (O extends unknown ? keyof O : never) : never>>, f: GuardInput<NoInfer<Guard.Output<G>>, B, E2, R2>): Guard<Guard.Input<G>, Guard.Output<G> & {
|
|
244
709
|
[k in K]: B;
|
|
245
|
-
},
|
|
710
|
+
}, Guard.Error<G> | E2, Guard.Services<G> | R2>;
|
|
246
711
|
};
|
|
247
712
|
//# sourceMappingURL=index.d.ts.map
|