@satoshibits/functional 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +242 -0
- package/dist/array-utils.d.mts +317 -0
- package/dist/array-utils.d.mts.map +1 -0
- package/dist/array-utils.mjs +370 -0
- package/dist/array-utils.mjs.map +1 -0
- package/dist/composition.d.mts +603 -0
- package/dist/composition.d.mts.map +1 -0
- package/dist/composition.mjs +516 -0
- package/dist/composition.mjs.map +1 -0
- package/dist/object-utils.d.mts +267 -0
- package/dist/object-utils.d.mts.map +1 -0
- package/dist/object-utils.mjs +258 -0
- package/dist/object-utils.mjs.map +1 -0
- package/dist/option.d.mts +622 -0
- package/dist/option.d.mts.map +1 -0
- package/dist/option.mjs +637 -0
- package/dist/option.mjs.map +1 -0
- package/dist/performance.d.mts +265 -0
- package/dist/performance.d.mts.map +1 -0
- package/dist/performance.mjs +453 -0
- package/dist/performance.mjs.map +1 -0
- package/dist/pipeline.d.mts +431 -0
- package/dist/pipeline.d.mts.map +1 -0
- package/dist/pipeline.mjs +460 -0
- package/dist/pipeline.mjs.map +1 -0
- package/dist/predicates.d.mts +722 -0
- package/dist/predicates.d.mts.map +1 -0
- package/dist/predicates.mjs +802 -0
- package/dist/predicates.mjs.map +1 -0
- package/dist/reader-result.d.mts +422 -0
- package/dist/reader-result.d.mts.map +1 -0
- package/dist/reader-result.mjs +758 -0
- package/dist/reader-result.mjs.map +1 -0
- package/dist/result.d.mts +684 -0
- package/dist/result.d.mts.map +1 -0
- package/dist/result.mjs +814 -0
- package/dist/result.mjs.map +1 -0
- package/dist/types.d.mts +439 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +191 -0
- package/dist/types.mjs.map +1 -0
- package/dist/validation.d.mts +622 -0
- package/dist/validation.d.mts.map +1 -0
- package/dist/validation.mjs +852 -0
- package/dist/validation.mjs.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module option
|
|
3
|
+
* @description Option/Maybe type for explicit null/undefined handling in a functional way.
|
|
4
|
+
* Provides a safe alternative to nullable values by wrapping them in a container type.
|
|
5
|
+
* Forces explicit handling of edge cases and eliminates null pointer exceptions.
|
|
6
|
+
* Inspired by functional programming languages like Haskell and Rust.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { Option, some, none, fromNullable, map, getOrElse } from './option.mts';
|
|
11
|
+
*
|
|
12
|
+
* // creating options
|
|
13
|
+
* const user = some({ id: '123', name: 'Alice' });
|
|
14
|
+
* const notFound = none();
|
|
15
|
+
* const maybeUser = fromNullable(localStorage.getItem('user'));
|
|
16
|
+
*
|
|
17
|
+
* // transforming values
|
|
18
|
+
* const userName = map((u: User) => u.name)(user);
|
|
19
|
+
*
|
|
20
|
+
* // extracting values safely
|
|
21
|
+
* const name = getOrElse(() => 'Anonymous')(userName);
|
|
22
|
+
*
|
|
23
|
+
* // chaining operations
|
|
24
|
+
* const greeting = pipe(
|
|
25
|
+
* fromNullable(getUserById(id)),
|
|
26
|
+
* map(u => u.name),
|
|
27
|
+
* map(name => `Hello, ${name}!`),
|
|
28
|
+
* getOrElse(() => 'Hello, stranger!')
|
|
29
|
+
* );
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @category Core
|
|
33
|
+
* @since 2025-07-03
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Option type representing a value that may or may not exist.
|
|
37
|
+
* @description A discriminated union type that forces explicit handling of null/undefined cases.
|
|
38
|
+
* An Option is either Some<T> (containing a value) or None (representing absence).
|
|
39
|
+
*
|
|
40
|
+
* @template T - The type of the value when present
|
|
41
|
+
*
|
|
42
|
+
* @category Core Types
|
|
43
|
+
* @since 2025-07-03
|
|
44
|
+
*/
|
|
45
|
+
export type Option<T> = Some<T> | None;
|
|
46
|
+
/**
|
|
47
|
+
* Represents a value that exists.
|
|
48
|
+
* @description The Some variant of Option, containing a non-null value.
|
|
49
|
+
*
|
|
50
|
+
* @template T - The type of the contained value
|
|
51
|
+
* @property {"Some"} _tag - Discriminant for pattern matching
|
|
52
|
+
* @property {T} value - The contained value
|
|
53
|
+
*
|
|
54
|
+
* @category Core Types
|
|
55
|
+
* @since 2025-07-03
|
|
56
|
+
*/
|
|
57
|
+
export interface Some<T> {
|
|
58
|
+
readonly _tag: 'Some';
|
|
59
|
+
readonly value: T;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Represents the absence of a value.
|
|
63
|
+
* @description The None variant of Option, representing no value.
|
|
64
|
+
*
|
|
65
|
+
* @property {"None"} _tag - Discriminant for pattern matching
|
|
66
|
+
*
|
|
67
|
+
* @category Core Types
|
|
68
|
+
* @since 2025-07-03
|
|
69
|
+
*/
|
|
70
|
+
export interface None {
|
|
71
|
+
readonly _tag: 'None';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a Some variant containing the provided value.
|
|
75
|
+
* @description Wraps a value in the Some variant of Option.
|
|
76
|
+
* Use this when you have a value that definitely exists.
|
|
77
|
+
*
|
|
78
|
+
* @template T - The type of the value to wrap
|
|
79
|
+
* @param {T} value - The value to wrap in Some
|
|
80
|
+
* @returns {Option<T>} A Some variant containing the value
|
|
81
|
+
*
|
|
82
|
+
* @category Constructors
|
|
83
|
+
* @example
|
|
84
|
+
* const user = some({ id: '123', name: 'Alice' });
|
|
85
|
+
* // => { _tag: 'Some', value: { id: '123', name: 'Alice' } }
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Wrapping a found value
|
|
89
|
+
* const found = database.find(id);
|
|
90
|
+
* const result = found ? some(found) : none();
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* // Creating from non-null assertion
|
|
94
|
+
* const config = getConfig();
|
|
95
|
+
* if (config.apiKey) {
|
|
96
|
+
* return some(config.apiKey);
|
|
97
|
+
* }
|
|
98
|
+
*
|
|
99
|
+
* @see none - Create an empty Option
|
|
100
|
+
* @see fromNullable - Create Option from nullable value
|
|
101
|
+
* @since 2025-07-03
|
|
102
|
+
*/
|
|
103
|
+
export declare const some: <T>(value: T) => Option<T>;
|
|
104
|
+
/**
|
|
105
|
+
* Creates a None variant representing no value.
|
|
106
|
+
* @description Creates the None variant of Option, representing absence of value.
|
|
107
|
+
* Use this when you want to explicitly represent "no value" in a type-safe way.
|
|
108
|
+
*
|
|
109
|
+
* @returns {Option<never>} A None variant
|
|
110
|
+
*
|
|
111
|
+
* @category Constructors
|
|
112
|
+
* @example
|
|
113
|
+
* const notFound = none();
|
|
114
|
+
* // => { _tag: 'None' }
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* // Representing search miss
|
|
118
|
+
* const user = users.find(u => u.id === targetId);
|
|
119
|
+
* return user ? some(user) : none();
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* // Empty configuration
|
|
123
|
+
* const apiKey = process.env.API_KEY;
|
|
124
|
+
* return apiKey ? some(apiKey) : none();
|
|
125
|
+
*
|
|
126
|
+
* @see some - Create an Option with a value
|
|
127
|
+
* @see fromNullable - Create Option from nullable value
|
|
128
|
+
* @since 2025-07-03
|
|
129
|
+
*/
|
|
130
|
+
export declare const none: () => Option<never>;
|
|
131
|
+
/**
|
|
132
|
+
* Creates an Option from a nullable value.
|
|
133
|
+
* @description Converts a nullable value into an Option.
|
|
134
|
+
* Returns Some if the value is not null/undefined, None otherwise.
|
|
135
|
+
* This is the primary way to bridge nullable APIs with Option.
|
|
136
|
+
*
|
|
137
|
+
* @template T - The type of the non-null value
|
|
138
|
+
* @param {T | null | undefined} value - The nullable value to convert
|
|
139
|
+
* @returns {Option<T>} Some if value exists, None otherwise
|
|
140
|
+
*
|
|
141
|
+
* @category Constructors
|
|
142
|
+
* @example
|
|
143
|
+
* const maybeUser = fromNullable(localStorage.getItem('user'));
|
|
144
|
+
* // => Some(userData) if exists, None if null
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* // Safe property access
|
|
148
|
+
* const email = fromNullable(user?.contact?.email);
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* // Array element access
|
|
152
|
+
* const firstItem = fromNullable(items[0]);
|
|
153
|
+
*
|
|
154
|
+
* @see some - Wrap a non-null value
|
|
155
|
+
* @see none - Create an empty Option
|
|
156
|
+
* @since 2025-07-03
|
|
157
|
+
*/
|
|
158
|
+
export declare const fromNullable: <T>(value: T | null | undefined) => Option<T>;
|
|
159
|
+
/**
|
|
160
|
+
* Creates an Option from a predicate function.
|
|
161
|
+
* Returns Some if the predicate is true, None otherwise.
|
|
162
|
+
*
|
|
163
|
+
* @category Constructors
|
|
164
|
+
* @example
|
|
165
|
+
* const positive = Option.fromPredicate((n: number) => n > 0);
|
|
166
|
+
* positive(5); // => Some(5)
|
|
167
|
+
* positive(-1); // => None
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* // Validation wrapper
|
|
171
|
+
* const validEmail = Option.fromPredicate((s: string) =>
|
|
172
|
+
* /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)
|
|
173
|
+
* );
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* // Range check
|
|
177
|
+
* const inRange = Option.fromPredicate((n: number) => n >= 0 && n <= 100);
|
|
178
|
+
*/
|
|
179
|
+
export declare const fromPredicate: <T>(predicate: (value: T) => boolean) => (value: T) => Option<T>;
|
|
180
|
+
/**
|
|
181
|
+
* Type guard to check if an Option is Some.
|
|
182
|
+
*
|
|
183
|
+
* @category Type Guards
|
|
184
|
+
* @example
|
|
185
|
+
* const opt = Option.fromNullable(getValue());
|
|
186
|
+
* if (Option.isSome(opt)) {
|
|
187
|
+
* console.log(opt.value); // TypeScript knows opt.value exists
|
|
188
|
+
* }
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* // Filtering array of options
|
|
192
|
+
* const values = options.filter(Option.isSome).map(opt => opt.value);
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* // Early return pattern
|
|
196
|
+
* if (!Option.isSome(result)) {
|
|
197
|
+
* return defaultValue;
|
|
198
|
+
* }
|
|
199
|
+
* return processValue(result.value);
|
|
200
|
+
*/
|
|
201
|
+
export declare const isSome: <T>(option: Option<T>) => option is Some<T>;
|
|
202
|
+
/**
|
|
203
|
+
* Type guard to check if an Option is None.
|
|
204
|
+
*
|
|
205
|
+
* @category Type Guards
|
|
206
|
+
* @example
|
|
207
|
+
* const user = findUser(id);
|
|
208
|
+
* if (Option.isNone(user)) {
|
|
209
|
+
* throw new Error('User not found');
|
|
210
|
+
* }
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* // Conditional rendering
|
|
214
|
+
* if (Option.isNone(data)) {
|
|
215
|
+
* return <LoadingSpinner />;
|
|
216
|
+
* }
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* // Validation check
|
|
220
|
+
* const validated = validate(input);
|
|
221
|
+
* if (Option.isNone(validated)) {
|
|
222
|
+
* return { error: 'Invalid input' };
|
|
223
|
+
* }
|
|
224
|
+
*/
|
|
225
|
+
export declare const isNone: <T>(option: Option<T>) => option is None;
|
|
226
|
+
/**
|
|
227
|
+
* Maps a function over the value in Some, does nothing for None.
|
|
228
|
+
*
|
|
229
|
+
* @category Transformations
|
|
230
|
+
* @example
|
|
231
|
+
* const doubled = Option.map((n: number) => n * 2);
|
|
232
|
+
* doubled(Option.some(5)); // => Some(10)
|
|
233
|
+
* doubled(Option.none()); // => None
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* // Transform user data
|
|
237
|
+
* const userName = pipe(
|
|
238
|
+
* findUser(id),
|
|
239
|
+
* Option.map(user => user.name),
|
|
240
|
+
* Option.map(name => name.toUpperCase())
|
|
241
|
+
* );
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* // Parse and transform
|
|
245
|
+
* const parsed = pipe(
|
|
246
|
+
* Option.fromNullable(jsonString),
|
|
247
|
+
* Option.map(str => JSON.parse(str)),
|
|
248
|
+
* Option.map(data => data.value)
|
|
249
|
+
* );
|
|
250
|
+
*/
|
|
251
|
+
export declare const map: <A, B>(fn: (value: A) => B) => (option: Option<A>) => Option<B>;
|
|
252
|
+
/**
|
|
253
|
+
* FlatMaps a function over the value in Some, does nothing for None.
|
|
254
|
+
* Also known as chain or bind in other libraries.
|
|
255
|
+
*
|
|
256
|
+
* @category Transformations
|
|
257
|
+
* @example
|
|
258
|
+
* const safeDivide = (n: number) =>
|
|
259
|
+
* n === 0 ? Option.none() : Option.some(10 / n);
|
|
260
|
+
*
|
|
261
|
+
* const result = pipe(
|
|
262
|
+
* Option.some(5),
|
|
263
|
+
* Option.flatMap(safeDivide)
|
|
264
|
+
* ); // => Some(2)
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* // Chaining optional operations
|
|
268
|
+
* const getManager = (employee: Employee) =>
|
|
269
|
+
* Option.fromNullable(employee.managerId)
|
|
270
|
+
* .pipe(Option.flatMap(id => findEmployee(id)));
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* // Validation chain
|
|
274
|
+
* const processUser = pipe(
|
|
275
|
+
* parseUser(input),
|
|
276
|
+
* Option.flatMap(validateAge),
|
|
277
|
+
* Option.flatMap(validateEmail)
|
|
278
|
+
* );
|
|
279
|
+
*/
|
|
280
|
+
export declare const flatMap: <A, B>(fn: (value: A) => Option<B>) => (option: Option<A>) => Option<B>;
|
|
281
|
+
/**
|
|
282
|
+
* Alias for flatMap - monadic bind operation.
|
|
283
|
+
*
|
|
284
|
+
* @category Transformations
|
|
285
|
+
* @see flatMap
|
|
286
|
+
*/
|
|
287
|
+
export declare const chain: <A, B>(fn: (value: A) => Option<B>) => (option: Option<A>) => Option<B>;
|
|
288
|
+
/**
|
|
289
|
+
* Returns the value if Some, otherwise returns the provided default.
|
|
290
|
+
*
|
|
291
|
+
* @category Extractors
|
|
292
|
+
* @example
|
|
293
|
+
* const value = Option.getOrElse(() => 'default')(maybeValue);
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* // Configuration with defaults
|
|
297
|
+
* const port = pipe(
|
|
298
|
+
* Option.fromNullable(process.env.PORT),
|
|
299
|
+
* Option.map(parseInt),
|
|
300
|
+
* Option.getOrElse(() => 3000)
|
|
301
|
+
* );
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* // User preferences
|
|
305
|
+
* const theme = pipe(
|
|
306
|
+
* getUserPreference('theme'),
|
|
307
|
+
* Option.getOrElse(() => 'light')
|
|
308
|
+
* );
|
|
309
|
+
*/
|
|
310
|
+
export declare const getOrElse: <T>(defaultValue: () => T) => (option: Option<T>) => T;
|
|
311
|
+
/**
|
|
312
|
+
* Returns the first Some option, or None if both are None.
|
|
313
|
+
* Useful for fallback chains.
|
|
314
|
+
*
|
|
315
|
+
* @category Combinations
|
|
316
|
+
* @example
|
|
317
|
+
* const config = Option.orElse(
|
|
318
|
+
* () => Option.fromNullable(process.env.API_KEY)
|
|
319
|
+
* )(Option.fromNullable(config.apiKey));
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* // Multiple fallbacks
|
|
323
|
+
* const findUser = (id: string) => pipe(
|
|
324
|
+
* findInCache(id),
|
|
325
|
+
* Option.orElse(() => findInDatabase(id)),
|
|
326
|
+
* Option.orElse(() => findInArchive(id))
|
|
327
|
+
* );
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* // Try alternative parsing
|
|
331
|
+
* const parsed = pipe(
|
|
332
|
+
* tryParseJSON(input),
|
|
333
|
+
* Option.orElse(() => tryParseYAML(input))
|
|
334
|
+
* );
|
|
335
|
+
*/
|
|
336
|
+
export declare const orElse: <T>(alternative: () => Option<T>) => (option: Option<T>) => Option<T>;
|
|
337
|
+
/**
|
|
338
|
+
* Filters the value in Some based on a predicate.
|
|
339
|
+
* Returns None if the predicate is false or if already None.
|
|
340
|
+
* Supports type guard predicates for type refinement.
|
|
341
|
+
*
|
|
342
|
+
* @category Refinements
|
|
343
|
+
* @example
|
|
344
|
+
* const positive = Option.filter((n: number) => n > 0);
|
|
345
|
+
* positive(Option.some(5)); // => Some(5)
|
|
346
|
+
* positive(Option.some(-1)); // => None
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* // Type narrowing with type guards
|
|
350
|
+
* const maybeString: Option<string | number> = Option.some(123);
|
|
351
|
+
* const isString = (v: unknown): v is string => typeof v === 'string';
|
|
352
|
+
* const onlyString: Option<string> = pipe(maybeString, Option.filter(isString));
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* // User authorization
|
|
356
|
+
* const authorizedUser = pipe(
|
|
357
|
+
* findUser(id),
|
|
358
|
+
* Option.filter(user => user.role === 'admin')
|
|
359
|
+
* );
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* // Valid data filtering
|
|
363
|
+
* const validData = pipe(
|
|
364
|
+
* parseData(input),
|
|
365
|
+
* Option.filter(data => data.length > 0),
|
|
366
|
+
* Option.filter(data => data.every(isValid))
|
|
367
|
+
* );
|
|
368
|
+
*/
|
|
369
|
+
export declare function filter<T, S extends T>(predicate: (value: T) => value is S): (option: Option<T>) => Option<S>;
|
|
370
|
+
export declare function filter<T>(predicate: (value: T) => boolean): (option: Option<T>) => Option<T>;
|
|
371
|
+
/**
|
|
372
|
+
* Pattern matching for Option types.
|
|
373
|
+
* Provides exhaustive handling of both Some and None cases.
|
|
374
|
+
*
|
|
375
|
+
* @category Pattern Matching
|
|
376
|
+
* @example
|
|
377
|
+
* const message = Option.match({
|
|
378
|
+
* some: (user) => `Hello, ${user.name}!`,
|
|
379
|
+
* none: () => 'Hello, guest!'
|
|
380
|
+
* })(maybeUser);
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* // React component rendering
|
|
384
|
+
* const UserProfile = ({ userId }: Props) => {
|
|
385
|
+
* const user = useUser(userId);
|
|
386
|
+
*
|
|
387
|
+
* return Option.match({
|
|
388
|
+
* some: (u) => <Profile user={u} />,
|
|
389
|
+
* none: () => <NotFound />
|
|
390
|
+
* })(user);
|
|
391
|
+
* };
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* // API response handling
|
|
395
|
+
* const response = await Option.match({
|
|
396
|
+
* some: async (data) => api.update(data),
|
|
397
|
+
* none: async () => api.create(defaults)
|
|
398
|
+
* })(existingData);
|
|
399
|
+
*/
|
|
400
|
+
export declare const match: <T, A, B>(patterns: {
|
|
401
|
+
some: (value: T) => A;
|
|
402
|
+
none: () => B;
|
|
403
|
+
}) => (option: Option<T>) => A | B;
|
|
404
|
+
/**
|
|
405
|
+
* Converts an Option to a nullable value.
|
|
406
|
+
* Some(value) becomes value, None becomes null.
|
|
407
|
+
*
|
|
408
|
+
* @category Conversions
|
|
409
|
+
* @example
|
|
410
|
+
* const value = Option.toNullable(maybeValue);
|
|
411
|
+
* localStorage.setItem('key', value ?? '');
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* // Database update
|
|
415
|
+
* const update = {
|
|
416
|
+
* name: Option.toNullable(maybeName),
|
|
417
|
+
* email: Option.toNullable(maybeEmail),
|
|
418
|
+
* phone: Option.toNullable(maybePhone)
|
|
419
|
+
* };
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* // JSON serialization
|
|
423
|
+
* const data = {
|
|
424
|
+
* id: user.id,
|
|
425
|
+
* nickname: Option.toNullable(user.nickname)
|
|
426
|
+
* };
|
|
427
|
+
*/
|
|
428
|
+
export declare const toNullable: <T>(option: Option<T>) => T | null;
|
|
429
|
+
/**
|
|
430
|
+
* Converts an Option to undefined if None.
|
|
431
|
+
* Some(value) becomes value, None becomes undefined.
|
|
432
|
+
*
|
|
433
|
+
* @category Conversions
|
|
434
|
+
* @example
|
|
435
|
+
* const params = {
|
|
436
|
+
* limit: 10,
|
|
437
|
+
* offset: Option.toUndefined(maybeOffset)
|
|
438
|
+
* };
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* // Optional chaining alternative
|
|
442
|
+
* const city = Option.toUndefined(
|
|
443
|
+
* Option.map((addr: Address) => addr.city)(maybeAddress)
|
|
444
|
+
* );
|
|
445
|
+
*/
|
|
446
|
+
export declare const toUndefined: <T>(option: Option<T>) => T | undefined;
|
|
447
|
+
/**
|
|
448
|
+
* Creates an Option from a function that might throw an error.
|
|
449
|
+
* Returns Some with the result if the function succeeds, None if it throws.
|
|
450
|
+
*
|
|
451
|
+
* @category Constructors
|
|
452
|
+
* @example
|
|
453
|
+
* const safeParse = (json: string) => Option.tryCatch(() => JSON.parse(json));
|
|
454
|
+
* safeParse('{"a":1}'); // => Some({ a: 1 })
|
|
455
|
+
* safeParse('invalid json'); // => None
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* // Safe file parsing
|
|
459
|
+
* const config = Option.tryCatch(() =>
|
|
460
|
+
* JSON.parse(fs.readFileSync('config.json', 'utf8'))
|
|
461
|
+
* );
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* // Safe URL parsing
|
|
465
|
+
* const url = Option.tryCatch(() => new URL(input));
|
|
466
|
+
*/
|
|
467
|
+
export declare const tryCatch: <T>(fn: () => T) => Option<T>;
|
|
468
|
+
/**
|
|
469
|
+
* Executes a side-effecting function on the value in Some.
|
|
470
|
+
* Returns the original Option unchanged.
|
|
471
|
+
*
|
|
472
|
+
* @category Side Effects
|
|
473
|
+
* @example
|
|
474
|
+
* const logValue = pipe(
|
|
475
|
+
* Option.some(42),
|
|
476
|
+
* Option.tap(value => console.log('Found value:', value))
|
|
477
|
+
* ); // logs "Found value: 42" and returns Some(42)
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* // Debug logging in a chain
|
|
481
|
+
* const result = pipe(
|
|
482
|
+
* getUserInput(),
|
|
483
|
+
* Option.tap(input => console.log('Raw input:', input)),
|
|
484
|
+
* Option.map(normalize),
|
|
485
|
+
* Option.tap(normalized => console.log('Normalized:', normalized)),
|
|
486
|
+
* Option.filter(isValid)
|
|
487
|
+
* );
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* // Side effects like analytics
|
|
491
|
+
* const trackEvent = pipe(
|
|
492
|
+
* findUser(id),
|
|
493
|
+
* Option.tap(user => analytics.track('user.found', { id: user.id }))
|
|
494
|
+
* );
|
|
495
|
+
*/
|
|
496
|
+
export declare const tap: <T>(fn: (value: T) => void) => (option: Option<T>) => Option<T>;
|
|
497
|
+
/**
|
|
498
|
+
* Namespace containing all Option utilities.
|
|
499
|
+
*
|
|
500
|
+
* @category Namespace
|
|
501
|
+
*/
|
|
502
|
+
export declare const Option: {
|
|
503
|
+
readonly some: <T>(value: T) => Option<T>;
|
|
504
|
+
readonly none: () => Option<never>;
|
|
505
|
+
readonly fromNullable: <T>(value: T | null | undefined) => Option<T>;
|
|
506
|
+
readonly fromPredicate: <T>(predicate: (value: T) => boolean) => (value: T) => Option<T>;
|
|
507
|
+
readonly tryCatch: <T>(fn: () => T) => Option<T>;
|
|
508
|
+
readonly isSome: <T>(option: Option<T>) => option is Some<T>;
|
|
509
|
+
readonly isNone: <T>(option: Option<T>) => option is None;
|
|
510
|
+
readonly map: <A, B>(fn: (value: A) => B) => (option: Option<A>) => Option<B>;
|
|
511
|
+
readonly flatMap: <A, B>(fn: (value: A) => Option<B>) => (option: Option<A>) => Option<B>;
|
|
512
|
+
readonly chain: <A, B>(fn: (value: A) => Option<B>) => (option: Option<A>) => Option<B>;
|
|
513
|
+
readonly getOrElse: <T>(defaultValue: () => T) => (option: Option<T>) => T;
|
|
514
|
+
readonly orElse: <T>(alternative: () => Option<T>) => (option: Option<T>) => Option<T>;
|
|
515
|
+
readonly filter: typeof filter;
|
|
516
|
+
readonly tap: <T>(fn: (value: T) => void) => (option: Option<T>) => Option<T>;
|
|
517
|
+
readonly match: <T, A, B>(patterns: {
|
|
518
|
+
some: (value: T) => A;
|
|
519
|
+
none: () => B;
|
|
520
|
+
}) => (option: Option<T>) => A | B;
|
|
521
|
+
readonly toNullable: <T>(option: Option<T>) => T | null;
|
|
522
|
+
readonly toUndefined: <T>(option: Option<T>) => T | undefined;
|
|
523
|
+
};
|
|
524
|
+
/**
|
|
525
|
+
* Combines two Options using a binary function.
|
|
526
|
+
* Returns None if either Option is None.
|
|
527
|
+
*
|
|
528
|
+
* @category Combinations
|
|
529
|
+
* @example
|
|
530
|
+
* const add = (a: number, b: number) => a + b;
|
|
531
|
+
* const sum = lift2(add)(Option.some(5), Option.some(3));
|
|
532
|
+
* // => Some(8)
|
|
533
|
+
*
|
|
534
|
+
* @example
|
|
535
|
+
* // Form validation
|
|
536
|
+
* const createUser = (name: string, email: string) => ({ name, email });
|
|
537
|
+
* const validUser = lift2(createUser)(
|
|
538
|
+
* validateName(input.name),
|
|
539
|
+
* validateEmail(input.email)
|
|
540
|
+
* );
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* // Coordinate operations
|
|
544
|
+
* const distance = (x: number, y: number) => Math.sqrt(x * x + y * y);
|
|
545
|
+
* const result = lift2(distance)(parseX(input), parseY(input));
|
|
546
|
+
*/
|
|
547
|
+
export declare const lift2: <A, B, C>(fn: (a: A, b: B) => C) => (optionA: Option<A>, optionB: Option<B>) => Option<C>;
|
|
548
|
+
/**
|
|
549
|
+
* Sequences an array of Options into an Option of array.
|
|
550
|
+
* Returns Some with all values if all are Some, None if any is None.
|
|
551
|
+
*
|
|
552
|
+
* @category Combinations
|
|
553
|
+
* @example
|
|
554
|
+
* const results = sequence([
|
|
555
|
+
* Option.some(1),
|
|
556
|
+
* Option.some(2),
|
|
557
|
+
* Option.some(3)
|
|
558
|
+
* ]);
|
|
559
|
+
* // => Some([1, 2, 3])
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* // Parse multiple values
|
|
563
|
+
* const numbers = sequence(
|
|
564
|
+
* inputs.map(input => parseNumber(input))
|
|
565
|
+
* );
|
|
566
|
+
*
|
|
567
|
+
* @example
|
|
568
|
+
* // Validate all fields
|
|
569
|
+
* const validatedFields = sequence([
|
|
570
|
+
* validateField('name', data.name),
|
|
571
|
+
* validateField('email', data.email),
|
|
572
|
+
* validateField('age', data.age)
|
|
573
|
+
* ]);
|
|
574
|
+
*/
|
|
575
|
+
export declare const sequence: <T>(options: Option<T>[]) => Option<T[]>;
|
|
576
|
+
/**
|
|
577
|
+
* Applies a function wrapped in an Option to a value wrapped in an Option.
|
|
578
|
+
*
|
|
579
|
+
* @category Apply
|
|
580
|
+
* @example
|
|
581
|
+
* const addOne = (n: number) => n + 1;
|
|
582
|
+
* const result = ap(Option.some(addOne))(Option.some(5));
|
|
583
|
+
* // => Some(6)
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* // Partial application with options
|
|
587
|
+
* const add = (a: number) => (b: number) => a + b;
|
|
588
|
+
* const maybeAdd5 = Option.map(add)(Option.some(5));
|
|
589
|
+
* const result = ap(maybeAdd5)(Option.some(3));
|
|
590
|
+
* // => Some(8)
|
|
591
|
+
*/
|
|
592
|
+
export declare const ap: <A, B>(optionFn: Option<(a: A) => B>) => (optionA: Option<A>) => Option<B>;
|
|
593
|
+
/**
|
|
594
|
+
* Sequences a struct of Options into an Option of a struct.
|
|
595
|
+
* Returns Some with the struct of all values if all are Some, None if any is None.
|
|
596
|
+
*
|
|
597
|
+
* @category Combinations
|
|
598
|
+
* @example
|
|
599
|
+
* const result = sequenceS({
|
|
600
|
+
* a: Option.some(1),
|
|
601
|
+
* b: Option.some('hello')
|
|
602
|
+
* });
|
|
603
|
+
* // => Some({ a: 1, b: 'hello' })
|
|
604
|
+
*
|
|
605
|
+
* @example
|
|
606
|
+
* // Form validation
|
|
607
|
+
* const validForm = sequenceS({
|
|
608
|
+
* name: validateName(input.name),
|
|
609
|
+
* email: validateEmail(input.email),
|
|
610
|
+
* age: validateAge(input.age)
|
|
611
|
+
* });
|
|
612
|
+
*
|
|
613
|
+
* @example
|
|
614
|
+
* // Configuration validation
|
|
615
|
+
* const config = sequenceS({
|
|
616
|
+
* apiKey: Option.fromNullable(process.env.API_KEY),
|
|
617
|
+
* port: Option.tryCatch(() => parseInt(process.env.PORT!)),
|
|
618
|
+
* debug: Option.fromNullable(process.env.DEBUG).pipe(Option.map(v => v === 'true'))
|
|
619
|
+
* });
|
|
620
|
+
*/
|
|
621
|
+
export declare const sequenceS: <T extends Record<string, Option<unknown>>>(struct: T) => Option<{ [K in keyof T]: T[K] extends Option<infer U> ? U : never; }>;
|
|
622
|
+
//# sourceMappingURL=option.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"option.d.mts","sourceRoot":"","sources":["../src/option.mts"],"names":[],"mappings":"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"}
|