ts-data-forge 1.2.0 → 1.3.0

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 CHANGED
@@ -139,6 +139,7 @@ expectType<{ x: number }, { x: number }>('=');
139
139
  // The following would cause a compile-time error:
140
140
  // expectType<User, Admin>("="); // Error: Type 'User' is not strictly equal to type 'Admin'.
141
141
 
142
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
143
  expectType<User, any>('!='); // Error: Comparisons with `any` are also strictly checked.
143
144
  ```
144
145
 
@@ -147,55 +148,53 @@ expectType<User, any>('!='); // Error: Comparisons with `any` are also strictly
147
148
  Handle nullable values and error-prone operations safely.
148
149
 
149
150
  ```typescript
150
- import { Optional, Result, pipe, match } from 'ts-data-forge';
151
+ import { match, Optional, pipe, Result } from 'ts-data-forge';
151
152
 
152
153
  // Optional for nullable values
153
154
  const maybeValue = Optional.some(42);
154
- const nothing = Optional.none;
155
155
 
156
156
  const doubled = Optional.map(maybeValue, (x) => x * 2);
157
- console.log(Optional.unwrapOr(doubled, 0)); // 84
157
+
158
+ assert.strictEqual(Optional.unwrapOr(doubled, 0), 84);
158
159
 
159
160
  // Result for error handling
160
161
  const success = Result.ok(42);
161
- const failure = Result.err('Something went wrong');
162
162
 
163
163
  const mapped = Result.map(success, (x) => x * 2);
164
- if (Result.isOk(mapped)) {
165
- console.log(mapped.value); // 84
166
- }
164
+
165
+ assert.deepStrictEqual(mapped, Result.ok(84));
167
166
 
168
167
  // Advanced pipe usage
169
- const processNumber = (input: number) =>
168
+ const processNumber = (input: number): Optional<number> =>
170
169
  pipe(input)
171
170
  .map((x) => x * 2) // Regular transformation
172
171
  .map((x) => x + 10) // Chain transformations
173
- .map((x) => (x > 50 ? Optional.some(x) : Optional.none)) // Convert to Optional
174
- .mapOptional((x) => x / 2).value; // Continue with Optional chain and get final Optional<number>
172
+ .map((x) => (x > 50 ? Optional.some(x / 2) : Optional.none)).value; // Get the result
173
+
174
+ assert.deepStrictEqual(processNumber(30), Optional.some(35));
175
175
 
176
- console.log(processNumber(30)); // Optional.some(35)
177
- console.log(processNumber(10)); // Optional.none
176
+ assert.deepStrictEqual(processNumber(10), Optional.none);
178
177
 
179
178
  // Pattern matching with match
180
179
  type Status = 'loading' | 'success' | 'error';
181
180
 
182
- const handleStatus = (status: Status, data?: string) =>
181
+ const handleStatus = (status: Status, data?: string): string =>
183
182
  match(status, {
184
183
  loading: 'Please wait...',
185
184
  success: `Data: ${data ?? 'No data'}`,
186
185
  error: 'An error occurred',
187
186
  });
188
187
 
189
- console.log(handleStatus('loading')); // 'Please wait...'
190
- console.log(handleStatus('success', 'Hello')); // 'Data: Hello'
191
- console.log(handleStatus('error')); // 'An error occurred'
188
+ assert.strictEqual(handleStatus('loading'), 'Please wait...');
189
+ assert.strictEqual(handleStatus('success', 'Hello'), 'Data: Hello');
190
+ assert.strictEqual(handleStatus('error'), 'An error occurred');
192
191
 
193
192
  // Pattern matching with Result
194
- const processResult = (result: Result<number, string>) =>
193
+ const processResult = (result: Result<number, string>): string =>
195
194
  Result.isOk(result) ? `Success: ${result.value}` : `Error: ${result.value}`;
196
195
 
197
- console.log(processResult(Result.ok(42))); // 'Success: 42'
198
- console.log(processResult(Result.err('Failed'))); // 'Error: Failed'
196
+ assert.strictEqual(processResult(Result.ok(42)), 'Success: 42');
197
+ assert.strictEqual(processResult(Result.err('Failed')), 'Error: Failed');
199
198
  ```
200
199
 
201
200
  ### 3. Number Utilities with `Num` and Branded Number Types
@@ -206,32 +205,35 @@ The `Num` object provides safe and convenient functions for numerical operations
206
205
  import { Num } from 'ts-data-forge';
207
206
 
208
207
  // Basic conversions
209
- const num = Num.from('123'); // 123
210
- const invalid = Num.from('abc'); // NaN
208
+ assert.strictEqual(Num.from('123'), 123);
209
+ assert.strictEqual(Number.isNaN(Num.from('abc')), true);
211
210
 
212
211
  // Range checking
213
212
  const inRange = Num.isInRange(0, 10);
214
- console.log(inRange(5)); // true
215
- console.log(inRange(0)); // true (inclusive lower bound)
216
- console.log(inRange(10)); // false (exclusive upper bound)
213
+
214
+ assert.strictEqual(inRange(5), true);
215
+ assert.strictEqual(inRange(0), true); // (inclusive lower bound)
216
+ assert.strictEqual(inRange(10), false); // (exclusive upper bound)
217
217
 
218
218
  // Clamping values
219
219
  const clamp = Num.clamp(0, 100);
220
- console.log(clamp(150)); // 100
221
- console.log(clamp(-10)); // 0
220
+
221
+ assert.strictEqual(clamp(150), 100);
222
+ assert.strictEqual(clamp(-10), 0);
222
223
 
223
224
  // Rounding utilities
224
225
  const round2 = Num.round(2);
225
- console.log(round2(3.14159)); // 3.14
226
226
 
227
- console.log(Num.roundAt(3.14159, 3)); // 3.142
228
- console.log(Num.roundToInt(3.7) satisfies Int); // 4
227
+ assert.strictEqual(round2(3.14159), 3.14);
228
+ assert.strictEqual(Num.roundAt(3.14159, 3), 3.142);
229
+ assert.strictEqual(Num.roundToInt(3.7), 4);
229
230
 
230
231
  // Type guards
231
- declare const value: number;
232
+ const value = 5; // example value
232
233
  if (Num.isNonZero(value)) {
233
234
  // value is guaranteed to be non-zero
234
235
  const result = Num.div(10, value); // Safe division
236
+ assert.strictEqual(result, 2);
235
237
  }
236
238
  ```
237
239
 
@@ -241,22 +243,16 @@ if (Num.isNonZero(value)) {
241
243
 
242
244
  ```typescript
243
245
  import {
244
- asInt,
245
- asUint,
246
246
  asFiniteNumber,
247
- asSafeInt,
247
+ asInt,
248
248
  asInt16,
249
- asUint32,
250
249
  asNonZeroInt,
251
250
  asPositiveInt,
252
- Int,
253
- Uint,
254
- FiniteNumber,
255
- SafeInt,
251
+ asSafeInt,
252
+ asUint,
253
+ asUint32,
256
254
  Int16,
257
- Uint32,
258
255
  NonZeroInt,
259
- PositiveInt,
260
256
  } from 'ts-data-forge';
261
257
 
262
258
  // Basic branded types
@@ -265,25 +261,42 @@ const unsigned = asUint(42); // Uint - non-negative integer
265
261
  const finite = asFiniteNumber(3.14); // FiniteNumber - finite floating-point
266
262
  const safeInt = asSafeInt(42); // SafeInt - integer in safe range
267
263
 
268
- const nonInteger = asInt(3.14); // This line causes a runtime error
264
+ assert.strictEqual(integer, 42);
265
+ assert.strictEqual(unsigned, 42);
266
+ assert.strictEqual(finite, 3.14);
267
+ assert.strictEqual(safeInt, 42);
268
+
269
+ // This line would cause a runtime error:
270
+ assert.throw(() => {
271
+ asInt(3.14);
272
+ });
269
273
 
270
274
  // Range-constrained types (16-bit, 32-bit)
271
275
  const int16 = asInt16(1000); // Int16: [-32768, 32767]
272
276
  const uint32 = asUint32(3000000000); // Uint32: [0, 4294967295]
277
+ assert.strictEqual(int16, 1000);
278
+ assert.strictEqual(uint32, 3000000000);
273
279
 
274
280
  // Non-zero and positive variants
275
281
  const nonZeroInt = asNonZeroInt(5); // NonZeroInt - excludes zero
276
282
  const positiveInt = asPositiveInt(10); // PositiveInt - excludes zero and negatives
283
+ assert.strictEqual(nonZeroInt, 5);
284
+ assert.strictEqual(positiveInt, 10);
277
285
 
278
286
  // Type-safe arithmetic with automatic clamping
279
287
  const sum = Int16.add(int16, asInt16(2000)); // Int16 (3000)
280
288
  const clamped = Int16.clamp(100000); // Int16 (32767 - clamped to MAX_VALUE)
289
+ assert.strictEqual(sum, 3000);
290
+ assert.strictEqual(clamped, 32767);
281
291
 
282
292
  // Safe division with non-zero types
283
293
  const ratio = NonZeroInt.div(asNonZeroInt(10), nonZeroInt); // No division by zero risk
294
+ assert.strictEqual(ratio, 2);
284
295
 
285
296
  // Random generation within type constraints
286
297
  const randomInt16 = Int16.random(); // Int16 (random value in valid range)
298
+ assert.strictEqual(-32768 <= randomInt16, true);
299
+ assert.strictEqual(randomInt16 <= 32767, true);
287
300
  ```
288
301
 
289
302
  ### 4. Array Utilities with `Arr`
@@ -291,39 +304,54 @@ const randomInt16 = Int16.random(); // Int16 (random value in valid range)
291
304
  The `Arr` object provides a rich set of functions for array manipulation.
292
305
 
293
306
  ```typescript
294
- import { Arr } from 'ts-data-forge';
307
+ import { Arr, expectType, Optional } from 'ts-data-forge';
295
308
 
296
309
  const numbers: readonly number[] = [1, 2, 3, 4, 5, 2, 3];
297
- const people = [
298
- { name: 'Alice', age: 30 },
299
- { name: 'Bob', age: 25 },
300
- { name: 'Charlie', age: 35 },
301
- ] as const;
302
310
 
303
311
  // Reduction
304
312
  const sum = Arr.sum(numbers);
305
- console.log(sum); // 20
306
313
 
307
- // Array creation
308
- const zeros: readonly [0, 0, 0, 0, 0] = Arr.zeros(5); // [0, 0, 0, 0, 0]
309
- const range: readonly [1, 2, 3] = Arr.range(1, 4); // [1, 2, 3]
314
+ assert.strictEqual(sum, 20);
310
315
 
311
316
  // Type-safe length checking
312
317
  if (Arr.isArrayAtLeastLength(numbers, 2)) {
313
- // numbers is now guaranteed to have at least 3 elements
318
+ // numbers is now guaranteed to have at least 2 elements
314
319
  expectType<typeof numbers, readonly [number, number, ...number[]]>('=');
315
- console.log(numbers[1]); // Safe access to index 2
320
+ assert.strictEqual(numbers[1], 2); // Safe access to index 1
316
321
  }
317
322
 
318
323
  // Take first n elements
319
- const firstThree = Arr.take(numbers, 3); // [1, 2, 3]
324
+ const firstThree = Arr.take(numbers, 3);
320
325
 
321
- // Find maximum by property
322
- const oldestPerson = Arr.maxBy(people, (person) => person.age);
323
- console.log(oldestPerson?.name); // 'Charlie'
326
+ assert.deepStrictEqual(firstThree, [1, 2, 3]);
324
327
 
325
328
  // Remove duplicates
326
- const unique = Arr.uniq(numbers); // [1, 2, 3, 4, 5]
329
+ const unique = Arr.uniq(numbers);
330
+
331
+ assert.deepStrictEqual(unique, [1, 2, 3, 4, 5]);
332
+
333
+ // Array creation
334
+ const zeros: readonly [0, 0, 0, 0, 0] = Arr.zeros(5);
335
+ assert.deepStrictEqual(zeros, [0, 0, 0, 0, 0]);
336
+
337
+ const range: readonly [1, 2, 3] = Arr.range(1, 4);
338
+ assert.deepStrictEqual(range, [1, 2, 3]);
339
+
340
+ const people = [
341
+ { name: 'Alice', age: 30 },
342
+ { name: 'Bob', age: 25 },
343
+ { name: 'Charlie', age: 35 },
344
+ ] as const;
345
+
346
+ // Find maximum by property
347
+ const oldestPerson = Arr.maxBy(people, (person) => person.age);
348
+ assert.deepStrictEqual(
349
+ oldestPerson,
350
+ Optional.some({ name: 'Charlie', age: 35 } as const),
351
+ );
352
+ if (Optional.isSome(oldestPerson)) {
353
+ assert.strictEqual(oldestPerson.value.name, 'Charlie');
354
+ }
327
355
  ```
328
356
 
329
357
  ### 5. Immutable Collections: `IMap` and `ISet`
@@ -331,7 +359,7 @@ const unique = Arr.uniq(numbers); // [1, 2, 3, 4, 5]
331
359
  Type-safe, immutable data structures.
332
360
 
333
361
  ```typescript
334
- import { IMap, ISet, pipe } from 'ts-data-forge';
362
+ import { Arr, IMap, ISet, Optional } from 'ts-data-forge';
335
363
 
336
364
  // IMap usage - immutable operations
337
365
  const originalMap = IMap.create<string, number>([]);
@@ -339,34 +367,37 @@ const mapWithOne = originalMap.set('one', 1);
339
367
  const mapWithTwo = mapWithOne.set('two', 2);
340
368
 
341
369
  // Original map is unchanged
342
- console.log(originalMap.size); // 0
343
- console.log(mapWithTwo.get('one')); // Optional.some(1)
344
- console.log(mapWithTwo.has('three')); // false
370
+ assert.strictEqual(originalMap.size, 0);
371
+ assert.deepStrictEqual(mapWithTwo.get('one'), Optional.some(1));
372
+
373
+ assert.strictEqual(mapWithTwo.has('three'), false);
345
374
 
346
375
  // Using pipe for fluent updates
347
- const idMap = pipe(Arr.seq(10))
348
- .map(Arr.map<number>(i => [i, i.toString()])
349
- .map(Arr.skip(1)) // [ [1, "1"], ..., [9, "9"]]
350
- .map(IMap.create<number, string>).value;
376
+ const sequence = Arr.seq(10); // [0, 1, 2, ..., 9]
377
+ const pairs = sequence.map(
378
+ (i) => [i, i.toString()] as readonly [number, string],
379
+ );
380
+ const skipped = Arr.skip(pairs, 1); // [[1, "1"], ..., [9, "9"]]
381
+ const idMap = IMap.create<number, string>(skipped);
351
382
 
352
- console.log(idMap.size); // 9
383
+ assert.strictEqual(idMap.size, 9);
353
384
 
354
385
  // Efficient batch updates with withMutations
355
386
  const idMapUpdated = idMap.withMutations([
356
- { type: 'set', key: 99, value: "99" },
357
- { type: 'update', key: 5, value: "five" },
387
+ { type: 'set', key: 99, value: '99' },
388
+ { type: 'update', key: 5, updater: () => 'five' },
358
389
  { type: 'delete', key: 4 },
359
390
  ]);
360
391
 
361
- console.log(idMapUpdated.size); // 9
392
+ assert.strictEqual(idMapUpdated.size, 9);
362
393
 
363
394
  // ISet usage
364
395
  const originalSet = ISet.create<number>([]);
365
396
  const setWithItems = originalSet.add(1).add(2).add(1); // Duplicate ignored
366
397
 
367
- console.log(originalSet.size); // 0 (unchanged)
368
- console.log(setWithItems.has(1)); // true
369
- console.log(setWithItems.size); // 2
398
+ assert.strictEqual(originalSet.size, 0); // (unchanged)
399
+ assert.strictEqual(setWithItems.has(1), true);
400
+ assert.strictEqual(setWithItems.size, 2);
370
401
  ```
371
402
 
372
403
  ### 6. Type Guards
@@ -374,9 +405,9 @@ console.log(setWithItems.size); // 2
374
405
  Safe type narrowing with comprehensive type guards.
375
406
 
376
407
  ```typescript
377
- import { isNonNullObject, isRecord, hasKey } from 'ts-data-forge';
408
+ import { hasKey, isNonNullObject, isRecord } from 'ts-data-forge';
378
409
 
379
- function processData(data: unknown) {
410
+ const processData = (data: unknown): string | undefined => {
380
411
  if (isRecord(data)) {
381
412
  // data is now UnknownRecord (= Readonly<Record<string, unknown>>)
382
413
  if (
@@ -384,17 +415,24 @@ function processData(data: unknown) {
384
415
  // data is now ReadonlyRecord<"name", unknown> & UnknownRecord
385
416
  typeof data.name === 'string'
386
417
  ) {
387
- console.log(`Hello, ${data.name}!`);
418
+ return `Hello, ${data.name}!`;
388
419
  }
389
420
  }
390
- }
421
+ return undefined;
422
+ };
391
423
 
392
424
  // Non-null object checking
393
- declare const value: unknown;
425
+ const value: unknown = { key: 'value' };
426
+
394
427
  if (isNonNullObject(value)) {
395
428
  // value is guaranteed to be a non-null object
396
- console.log(Object.keys(value));
429
+ assert.deepStrictEqual(Object.keys(value), ['key']);
397
430
  }
431
+
432
+ // Example usage
433
+ assert.strictEqual(processData({ name: 'Alice' }), 'Hello, Alice!');
434
+ assert.strictEqual(processData({ age: 30 }), undefined);
435
+ assert.strictEqual(processData('not an object'), undefined);
398
436
  ```
399
437
 
400
438
  ### 7. Iteration with `range`
@@ -405,18 +443,27 @@ Generate ranges for iteration and array creation.
405
443
  import { range } from 'ts-data-forge';
406
444
 
407
445
  // Traditional for loop using range
446
+ const values: number[] = [];
408
447
  for (const i of range(0, 5)) {
409
- console.log(i); // 0, 1, 2, 3, 4
448
+ values.push(i);
410
449
  }
411
450
 
451
+ assert.deepStrictEqual(values, [0, 1, 2, 3, 4]);
452
+
412
453
  // Create arrays from ranges
413
- const numbers = Array.from(range(1, 4)); // [1, 2, 3]
414
- const squares = Array.from(range(1, 6), (x) => x * x); // [1, 4, 9, 16, 25]
454
+ const numbers = Array.from(range(1, 4));
455
+ const squares = Array.from(range(1, 6), (x) => x * x);
456
+
457
+ assert.deepStrictEqual(numbers, [1, 2, 3]);
458
+ assert.deepStrictEqual(squares, [1, 4, 9, 16, 25]);
415
459
 
416
460
  // Step ranges
461
+ const stepValues: number[] = [];
417
462
  for (const i of range(0, 10, 2)) {
418
- console.log(i); // 0, 2, 4, 6, 8
463
+ stepValues.push(i);
419
464
  }
465
+
466
+ assert.deepStrictEqual(stepValues, [0, 2, 4, 6, 8]);
420
467
  ```
421
468
 
422
469
  ### 8. Mutability Utilities with `castMutable`
@@ -424,23 +471,23 @@ for (const i of range(0, 10, 2)) {
424
471
  Safely work with readonly types when interfacing with mutable APIs.
425
472
 
426
473
  ```tsx
427
- import { Autocomplete } from '@mui/material';
428
474
  import { castMutable } from 'ts-data-forge';
429
475
 
430
- const readonlyOptions: readonly string[] = ['Option 1', 'Option 2', 'Option 3'];
476
+ // Example: Material-UI Autocomplete
477
+ import { Autocomplete, TextField } from '@mui/material';
431
478
 
432
- const SomeComponent: React.FC = () => {
433
- // Component implementation
434
- return (
435
- <Autocomplete
436
- // Use castMutable to safely pass readonly array to mutable API. This is safer than casting with `as`, as it simply changes type `readonly T[]` to `T[]`.
437
- options={castMutable(readonlyOptions)}
438
- // ...
439
- />
440
- );
441
- };
479
+ export const SomeComponent: React.FC = () => (
480
+ <Autocomplete
481
+ options={castMutable(readonlyOptions)}
482
+ renderInput={(params) => (
483
+ <TextField {...params} placeholder="Select an option" />
484
+ )}
485
+ />
486
+ );
487
+
488
+ const readonlyOptions: readonly string[] = ['Option 1', 'Option 2', 'Option 3'];
442
489
 
443
- // Immer.js example - draft properties need mutable types
490
+ // Immer.js example
444
491
  import { produce } from 'immer';
445
492
 
446
493
  type State = Readonly<{
@@ -458,7 +505,8 @@ const updatedState = produce(initialState, (draft) => {
458
505
  draft.items = castMutable(newItems); // Safe cast for assignment
459
506
  });
460
507
 
461
- console.log(updatedState.items); // ['newItem1', 'newItem2']
508
+ assert.deepStrictEqual(initialState.items, ['item1', 'item2']);
509
+ assert.deepStrictEqual(updatedState.items, ['newItem1', 'newItem2']);
462
510
  ```
463
511
 
464
512
  ## Modules Overview
package/dist/index.d.mts CHANGED
@@ -8,4 +8,5 @@ export * from './json/index.mjs';
8
8
  export * from './number/index.mjs';
9
9
  export * from './object/index.mjs';
10
10
  export * from './others/index.mjs';
11
+ export * from './promise/index.mjs';
11
12
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
package/dist/index.mjs CHANGED
@@ -58,4 +58,5 @@ export { mapNullable } from './others/map-nullable.mjs';
58
58
  export { memoizeFunction } from './others/memoize-function.mjs';
59
59
  export { tp } from './others/tuple.mjs';
60
60
  export { unknownToString } from './others/unknown-to-string.mjs';
61
+ export { createPromise } from './promise/promise.mjs';
61
62
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,2 @@
1
+ export * from './promise.mjs';
2
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/promise/index.mts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createPromise } from './promise.mjs';
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { Result } from '../functional/index.mjs';
2
+ /**
3
+ * Creates a Promise that wraps the result in a Result type for type-safe error handling.
4
+ * This function is an alternative to `new Promise(executor)` that provides enhanced type safety
5
+ * by returning a Result type instead of throwing exceptions.
6
+ *
7
+ * @template S - The type of successful value
8
+ * @template E - The type of error value
9
+ * @param executor - Function that takes resolve and reject callbacks
10
+ * @returns A Promise that resolves to a Result containing either success or error
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const result = await createPromise<string, Error>((resolve, reject) => {
15
+ * setTimeout(() => {
16
+ * if (Math.random() > 0.5) {
17
+ * resolve("Success!");
18
+ * } else {
19
+ * reject(new Error("Failed"));
20
+ * }
21
+ * }, 1000);
22
+ * });
23
+ *
24
+ * if (result.isOk()) {
25
+ * console.log(result.value); // "Success!"
26
+ * } else {
27
+ * console.log(result.error); // Error: Failed
28
+ * }
29
+ * ```
30
+ */
31
+ export declare const createPromise: <S, E>(executor: (resolve: (value: S) => void, reject: (reason?: E) => void) => void) => Promise<Result<S, E>>;
32
+ //# sourceMappingURL=promise.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promise.d.mts","sourceRoot":"","sources":["../../src/promise/promise.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,EAChC,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,KAAK,IAAI,KAC5E,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAIK,CAAC"}
@@ -0,0 +1,38 @@
1
+ import '../functional/optional.mjs';
2
+ import { Result } from '../functional/result.mjs';
3
+
4
+ /**
5
+ * Creates a Promise that wraps the result in a Result type for type-safe error handling.
6
+ * This function is an alternative to `new Promise(executor)` that provides enhanced type safety
7
+ * by returning a Result type instead of throwing exceptions.
8
+ *
9
+ * @template S - The type of successful value
10
+ * @template E - The type of error value
11
+ * @param executor - Function that takes resolve and reject callbacks
12
+ * @returns A Promise that resolves to a Result containing either success or error
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const result = await createPromise<string, Error>((resolve, reject) => {
17
+ * setTimeout(() => {
18
+ * if (Math.random() > 0.5) {
19
+ * resolve("Success!");
20
+ * } else {
21
+ * reject(new Error("Failed"));
22
+ * }
23
+ * }, 1000);
24
+ * });
25
+ *
26
+ * if (result.isOk()) {
27
+ * console.log(result.value); // "Success!"
28
+ * } else {
29
+ * console.log(result.error); // Error: Failed
30
+ * }
31
+ * ```
32
+ */
33
+ const createPromise = (executor) =>
34
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
35
+ Result.fromPromise(new Promise(executor));
36
+
37
+ export { createPromise };
38
+ //# sourceMappingURL=promise.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promise.mjs","sources":["../../src/promise/promise.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AACI,MAAM,aAAa,GAAG,CAC3B,QAA6E;AAE7E;AACA,MAAM,CAAC,WAAW,CAAC,IAAI,OAAO,CAAI,QAAQ,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-data-forge",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript",
@@ -45,15 +45,20 @@
45
45
  "gi": "npm run z:node-esm -- ./scripts/cmd/gi.mjs",
46
46
  "lint": "eslint .",
47
47
  "lint:fix": "eslint . --fix",
48
+ "lint:samples": "eslint ./samples",
48
49
  "md": "markdownlint-cli2",
49
50
  "test": "npm run z:vitest -- run",
50
51
  "test:cov": "npm run z:vitest -- run --coverage",
51
52
  "test:cov:ui": "vite preview --outDir ./coverage",
53
+ "test:samples": "vitest --config ./samples/vitest.config.ts",
52
54
  "test:ui": "npm run z:vitest -- --ui",
53
55
  "testw": "npm run z:vitest -- watch",
56
+ "testw:samples": "npm run test:samples -- watch",
54
57
  "tsc": "tsc --noEmit",
55
- "tscw": "tsc --noEmit --watch",
58
+ "tscw": "tsc --noEmit --watch -p ./tsconfig.json",
59
+ "tscw:samples": "tsc --noEmit --watch -p ./samples/tsconfig.json",
56
60
  "type-check": "tsc --noEmit",
61
+ "type-check:samples": "tsc --noEmit -p ./samples/tsconfig.json",
57
62
  "update-packages": "npx npm-check-updates -u --install always --reject @types/node",
58
63
  "z:node-esm": "node --import tsx/esm",
59
64
  "z:vitest": "vitest --config ./configs/vitest.config.ts"
@@ -62,10 +67,13 @@
62
67
  "ts-type-forge": "^2.0.3"
63
68
  },
64
69
  "devDependencies": {
65
- "@eslint/js": "^9.29.0",
70
+ "@emotion/react": "^11.14.0",
71
+ "@emotion/styled": "^11.14.1",
72
+ "@eslint/js": "^9.30.0",
73
+ "@mui/material": "^7.1.1",
66
74
  "@rollup/plugin-replace": "^6.0.2",
67
75
  "@rollup/plugin-strip": "^3.0.4",
68
- "@rollup/plugin-typescript": "^12.1.2",
76
+ "@rollup/plugin-typescript": "^12.1.4",
69
77
  "@semantic-release/changelog": "^6.0.3",
70
78
  "@semantic-release/commit-analyzer": "^13.0.1",
71
79
  "@semantic-release/exec": "^7.1.0",
@@ -78,17 +86,18 @@
78
86
  "@vitest/ui": "^3.2.4",
79
87
  "conventional-changelog-conventionalcommits": "^9.0.0",
80
88
  "cspell": "^9.1.1",
81
- "eslint": "^9.29.0",
89
+ "eslint": "^9.30.0",
82
90
  "fast-glob": "^3.3.3",
91
+ "immer": "^10.1.1",
83
92
  "markdownlint-cli2": "^0.18.1",
84
93
  "prettier": "^3.5.3",
85
94
  "prettier-plugin-organize-imports": "^4.1.0",
86
- "prettier-plugin-packagejson": "^2.5.15",
87
- "rollup": "^4.44.0",
95
+ "prettier-plugin-packagejson": "^2.5.17",
96
+ "rollup": "^4.44.1",
88
97
  "semantic-release": "^24.2.5",
89
- "ts-repo-utils": "^2.2.0",
98
+ "ts-repo-utils": "^3.0.1",
90
99
  "tsx": "^4.20.3",
91
- "typedoc": "^0.28.5",
100
+ "typedoc": "^0.28.6",
92
101
  "typedoc-plugin-markdown": "^4.7.0",
93
102
  "typescript": "^5.8.3",
94
103
  "typescript-eslint": "^8.34.1",
package/src/index.mts CHANGED
@@ -8,3 +8,4 @@ export * from './json/index.mjs';
8
8
  export * from './number/index.mjs';
9
9
  export * from './object/index.mjs';
10
10
  export * from './others/index.mjs';
11
+ export * from './promise/index.mjs';
@@ -0,0 +1 @@
1
+ export * from './promise.mjs';
@@ -0,0 +1,38 @@
1
+ import { Result } from '../functional/index.mjs';
2
+
3
+ /**
4
+ * Creates a Promise that wraps the result in a Result type for type-safe error handling.
5
+ * This function is an alternative to `new Promise(executor)` that provides enhanced type safety
6
+ * by returning a Result type instead of throwing exceptions.
7
+ *
8
+ * @template S - The type of successful value
9
+ * @template E - The type of error value
10
+ * @param executor - Function that takes resolve and reject callbacks
11
+ * @returns A Promise that resolves to a Result containing either success or error
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const result = await createPromise<string, Error>((resolve, reject) => {
16
+ * setTimeout(() => {
17
+ * if (Math.random() > 0.5) {
18
+ * resolve("Success!");
19
+ * } else {
20
+ * reject(new Error("Failed"));
21
+ * }
22
+ * }, 1000);
23
+ * });
24
+ *
25
+ * if (result.isOk()) {
26
+ * console.log(result.value); // "Success!"
27
+ * } else {
28
+ * console.log(result.error); // Error: Failed
29
+ * }
30
+ * ```
31
+ */
32
+ export const createPromise = <S, E>(
33
+ executor: (resolve: (value: S) => void, reject: (reason?: E) => void) => void,
34
+ ): Promise<Result<S, E>> =>
35
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
36
+ Result.fromPromise(new Promise<S>(executor)) satisfies Promise<
37
+ Result<S, unknown>
38
+ > as Promise<Result<S, E>>;