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 +145 -97
- package/dist/index.d.mts +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/promise/index.d.mts +2 -0
- package/dist/promise/index.d.mts.map +1 -0
- package/dist/promise/index.mjs +2 -0
- package/dist/promise/index.mjs.map +1 -0
- package/dist/promise/promise.d.mts +32 -0
- package/dist/promise/promise.d.mts.map +1 -0
- package/dist/promise/promise.mjs +38 -0
- package/dist/promise/promise.mjs.map +1 -0
- package/package.json +18 -9
- package/src/index.mts +1 -0
- package/src/promise/index.mts +1 -0
- package/src/promise/promise.mts +38 -0
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 {
|
|
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
|
-
|
|
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
|
-
|
|
165
|
-
|
|
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)) //
|
|
174
|
-
|
|
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
|
-
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
198
|
-
|
|
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
|
-
|
|
210
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
-
|
|
221
|
-
|
|
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
|
-
|
|
228
|
-
|
|
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
|
-
|
|
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
|
-
|
|
247
|
+
asInt,
|
|
248
248
|
asInt16,
|
|
249
|
-
asUint32,
|
|
250
249
|
asNonZeroInt,
|
|
251
250
|
asPositiveInt,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
318
|
+
// numbers is now guaranteed to have at least 2 elements
|
|
314
319
|
expectType<typeof numbers, readonly [number, number, ...number[]]>('=');
|
|
315
|
-
|
|
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);
|
|
324
|
+
const firstThree = Arr.take(numbers, 3);
|
|
320
325
|
|
|
321
|
-
|
|
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);
|
|
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,
|
|
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
|
-
|
|
343
|
-
|
|
344
|
-
|
|
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
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
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:
|
|
357
|
-
{ type: 'update', key: 5,
|
|
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
|
-
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
|
408
|
+
import { hasKey, isNonNullObject, isRecord } from 'ts-data-forge';
|
|
378
409
|
|
|
379
|
-
|
|
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
|
-
|
|
418
|
+
return `Hello, ${data.name}!`;
|
|
388
419
|
}
|
|
389
420
|
}
|
|
390
|
-
|
|
421
|
+
return undefined;
|
|
422
|
+
};
|
|
391
423
|
|
|
392
424
|
// Non-null object checking
|
|
393
|
-
|
|
425
|
+
const value: unknown = { key: 'value' };
|
|
426
|
+
|
|
394
427
|
if (isNonNullObject(value)) {
|
|
395
428
|
// value is guaranteed to be a non-null object
|
|
396
|
-
|
|
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
|
-
|
|
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));
|
|
414
|
-
const squares = Array.from(range(1, 6), (x) => x * x);
|
|
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
|
-
|
|
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
|
-
|
|
476
|
+
// Example: Material-UI Autocomplete
|
|
477
|
+
import { Autocomplete, TextField } from '@mui/material';
|
|
431
478
|
|
|
432
|
-
const SomeComponent: React.FC = () =>
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
|
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
|
-
|
|
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
package/dist/index.d.mts.map
CHANGED
|
@@ -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
|
package/dist/index.mjs.map
CHANGED
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/promise/index.mts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
|
|
@@ -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.
|
|
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
|
-
"@
|
|
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.
|
|
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.
|
|
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.
|
|
87
|
-
"rollup": "^4.44.
|
|
95
|
+
"prettier-plugin-packagejson": "^2.5.17",
|
|
96
|
+
"rollup": "^4.44.1",
|
|
88
97
|
"semantic-release": "^24.2.5",
|
|
89
|
-
"ts-repo-utils": "^
|
|
98
|
+
"ts-repo-utils": "^3.0.1",
|
|
90
99
|
"tsx": "^4.20.3",
|
|
91
|
-
"typedoc": "^0.28.
|
|
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
|
@@ -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>>;
|