ts-data-forge 6.4.0 → 6.6.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 +5 -3
- package/dist/array/impl/array-utils-element-access.d.mts +5 -5
- package/dist/array/impl/array-utils-element-access.mjs +4 -4
- package/dist/array/impl/array-utils-iterators.d.mts +1 -1
- package/dist/array/impl/array-utils-iterators.mjs +1 -1
- package/dist/array/impl/array-utils-modification.d.mts +4 -4
- package/dist/array/impl/array-utils-reducing-value.d.mts +5 -5
- package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
- package/dist/array/impl/array-utils-reducing-value.mjs +1 -0
- package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
- package/dist/array/impl/array-utils-search.d.mts +8 -8
- package/dist/array/impl/array-utils-set-op.d.mts.map +1 -1
- package/dist/array/impl/array-utils-set-op.mjs +3 -1
- package/dist/array/impl/array-utils-set-op.mjs.map +1 -1
- package/dist/array/impl/array-utils-size.d.mts +1 -1
- package/dist/array/impl/array-utils-size.mjs +1 -1
- package/dist/array/impl/array-utils-slice-clamped.d.mts +1 -1
- package/dist/array/impl/array-utils-slicing.d.mts +3 -3
- package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-validation.d.mts +7 -7
- package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-validation.mjs +22 -12
- package/dist/array/impl/array-utils-validation.mjs.map +1 -1
- package/dist/collections/imap-mapped.d.mts +5 -12
- package/dist/collections/imap-mapped.d.mts.map +1 -1
- package/dist/collections/imap-mapped.mjs.map +1 -1
- package/dist/collections/imap.d.mts +24 -28
- package/dist/collections/imap.d.mts.map +1 -1
- package/dist/collections/imap.mjs +1 -1
- package/dist/collections/imap.mjs.map +1 -1
- package/dist/collections/iset-mapped.d.mts +8 -14
- package/dist/collections/iset-mapped.d.mts.map +1 -1
- package/dist/collections/iset-mapped.mjs.map +1 -1
- package/dist/collections/iset.d.mts +9 -23
- package/dist/collections/iset.d.mts.map +1 -1
- package/dist/collections/iset.mjs +1 -0
- package/dist/collections/iset.mjs.map +1 -1
- package/dist/entry-point.mjs +1 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/functional/optional/impl/optional-is-optional.d.mts +1 -1
- package/dist/functional/optional/impl/optional-is-optional.d.mts.map +1 -1
- package/dist/functional/optional/impl/optional-is-optional.mjs +6 -5
- package/dist/functional/optional/impl/optional-is-optional.mjs.map +1 -1
- package/dist/functional/optional/impl/optional-some.d.mts.map +1 -1
- package/dist/functional/optional/impl/optional-some.mjs.map +1 -1
- package/dist/functional/optional/impl/optional-zip.d.mts +1 -1
- package/dist/functional/optional/impl/optional-zip.mjs +1 -1
- package/dist/functional/result/impl/result-err.d.mts.map +1 -1
- package/dist/functional/result/impl/result-err.mjs.map +1 -1
- package/dist/functional/result/impl/result-is-result.d.mts +1 -1
- package/dist/functional/result/impl/result-is-result.mjs +1 -1
- package/dist/functional/result/impl/result-ok.d.mts.map +1 -1
- package/dist/functional/result/impl/result-ok.mjs.map +1 -1
- package/dist/functional/result/impl/result-unwrap-err-throw.mjs +1 -0
- package/dist/functional/result/impl/result-unwrap-err-throw.mjs.map +1 -1
- package/dist/functional/result/impl/result-unwrap-throw.mjs +1 -0
- package/dist/functional/result/impl/result-unwrap-throw.mjs.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-err.d.mts.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-err.mjs.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.d.mts +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.mjs +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-ok.d.mts.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-ok.mjs.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs +1 -0
- package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs +1 -0
- package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs +1 -0
- package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-warn.d.mts.map +1 -1
- package/dist/functional/ternary-result/impl/ternary-result-warn.mjs.map +1 -1
- package/dist/guard/has-key.d.mts +3 -1
- package/dist/guard/has-key.d.mts.map +1 -1
- package/dist/guard/has-key.mjs +6 -2
- package/dist/guard/has-key.mjs.map +1 -1
- package/dist/guard/is-non-null-object.d.mts.map +1 -1
- package/dist/guard/is-non-null-object.mjs +3 -1
- package/dist/guard/is-non-null-object.mjs.map +1 -1
- package/dist/guard/is-record.d.mts +2 -2
- package/dist/guard/is-record.mjs +2 -2
- package/dist/guard/is-type.d.mts +15 -15
- package/dist/guard/is-type.mjs +15 -15
- package/dist/guard/key-is-in.d.mts.map +1 -1
- package/dist/guard/key-is-in.mjs +3 -1
- package/dist/guard/key-is-in.mjs.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/json/json.d.mts +3 -3
- package/dist/json/json.mjs +4 -3
- package/dist/json/json.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-safe-int.mjs +2 -2
- package/dist/number/branded-types/positive-safe-int.mjs +1 -1
- package/dist/number/branded-types/safe-int.mjs +2 -2
- package/dist/number/branded-types/safe-uint.mjs +1 -1
- package/dist/number/num.mjs +1 -1
- package/dist/object/object.d.mts +36 -8
- package/dist/object/object.d.mts.map +1 -1
- package/dist/object/object.mjs +28 -6
- package/dist/object/object.mjs.map +1 -1
- package/dist/others/fast-deep-equal.d.mts +8 -0
- package/dist/others/fast-deep-equal.d.mts.map +1 -0
- package/dist/others/fast-deep-equal.mjs +72 -0
- package/dist/others/fast-deep-equal.mjs.map +1 -0
- package/dist/others/index.d.mts +1 -0
- package/dist/others/index.d.mts.map +1 -1
- package/dist/others/index.mjs +1 -0
- package/dist/others/index.mjs.map +1 -1
- package/package.json +34 -29
- package/src/array/impl/array-utils-creation.test.mts +13 -10
- package/src/array/impl/array-utils-element-access.mts +5 -5
- package/src/array/impl/array-utils-element-access.test.mts +5 -5
- package/src/array/impl/array-utils-iterators.mts +1 -1
- package/src/array/impl/array-utils-iterators.test.mts +6 -6
- package/src/array/impl/array-utils-modification.mts +4 -4
- package/src/array/impl/array-utils-modification.test.mts +12 -12
- package/src/array/impl/array-utils-overload-type-error.test.mts +1 -1
- package/src/array/impl/array-utils-reducing-value.mts +6 -5
- package/src/array/impl/array-utils-reducing-value.test.mts +9 -9
- package/src/array/impl/array-utils-search.mts +8 -8
- package/src/array/impl/array-utils-search.test.mts +35 -35
- package/src/array/impl/array-utils-set-op.mts +1 -0
- package/src/array/impl/array-utils-set-op.test.mts +2 -2
- package/src/array/impl/array-utils-size.mts +1 -1
- package/src/array/impl/array-utils-size.test.mts +1 -1
- package/src/array/impl/array-utils-slice-clamped.mts +1 -1
- package/src/array/impl/array-utils-slice-clamped.test.mts +5 -5
- package/src/array/impl/array-utils-slicing.mts +3 -3
- package/src/array/impl/array-utils-slicing.test.mts +5 -5
- package/src/array/impl/array-utils-transformation.mts +1 -1
- package/src/array/impl/array-utils-transformation.test.mts +53 -53
- package/src/array/impl/array-utils-validation.mts +18 -10
- package/src/array/impl/array-utils-validation.test.mts +34 -29
- package/src/array/impl/array.test.mts +1 -1
- package/src/collections/imap-mapped.mts +4 -10
- package/src/collections/imap-mapped.test.mts +9 -9
- package/src/collections/imap.mts +24 -27
- package/src/collections/imap.test.mts +6 -6
- package/src/collections/iset-mapped.mts +12 -16
- package/src/collections/iset-mapped.test.mts +6 -6
- package/src/collections/iset.mts +14 -25
- package/src/collections/queue.test.mts +2 -1
- package/src/collections/stack.test.mts +3 -3
- package/src/functional/optional/impl/optional-is-optional.mts +6 -6
- package/src/functional/optional/impl/optional-some.mts +5 -4
- package/src/functional/optional/impl/optional-zip.mts +1 -1
- package/src/functional/result/impl/result-err.mts +5 -4
- package/src/functional/result/impl/result-is-result.mts +1 -1
- package/src/functional/result/impl/result-ok.mts +5 -4
- package/src/functional/result.test.mts +2 -2
- package/src/functional/ternary-result/impl/ternary-result-err.mts +5 -4
- package/src/functional/ternary-result/impl/ternary-result-is-ternary-result.mts +1 -1
- package/src/functional/ternary-result/impl/ternary-result-ok.mts +5 -4
- package/src/functional/ternary-result/impl/ternary-result-warn.mts +6 -5
- package/src/guard/has-key.mts +6 -2
- package/src/guard/is-error.test.mts +1 -1
- package/src/guard/is-non-empty-string.test.mts +1 -1
- package/src/guard/is-non-null-object.mts +1 -0
- package/src/guard/is-non-null-object.test.mts +4 -3
- package/src/guard/is-primitive.test.mts +1 -1
- package/src/guard/is-record.mts +2 -2
- package/src/guard/is-record.test.mts +2 -2
- package/src/guard/is-type.mts +15 -15
- package/src/guard/is-type.test.mts +2 -2
- package/src/guard/key-is-in.mts +3 -1
- package/src/json/json.mts +4 -3
- package/src/json/json.test.mts +20 -19
- package/src/number/branded-types/non-zero-safe-int.mts +2 -2
- package/src/number/branded-types/positive-safe-int.mts +1 -1
- package/src/number/branded-types/safe-int.mts +2 -2
- package/src/number/branded-types/safe-uint.mts +1 -1
- package/src/number/num.mts +1 -1
- package/src/object/object.mts +54 -8
- package/src/object/object.test.mts +70 -7
- package/src/others/cast-mutable.test.mts +3 -3
- package/src/others/cast-readonly.test.mts +10 -5
- package/src/others/fast-deep-equal.mts +98 -0
- package/src/others/fast-deep-equal.test.mts +771 -0
- package/src/others/index.mts +1 -0
- package/src/others/map-nullable.test.mts +8 -8
- package/src/others/memoize-function.test.mts +20 -8
- package/src/others/unknown-to-string.test.mts +8 -8
|
@@ -2,13 +2,13 @@ import { ISetMapped } from './iset-mapped.mjs';
|
|
|
2
2
|
|
|
3
3
|
const toKey = (a: Readonly<{ v: number }>): number => a.v;
|
|
4
4
|
|
|
5
|
-
const fromKey = (k: number): Readonly<{ v: number }> => ({ v: k });
|
|
5
|
+
const fromKey = (k: number): Readonly<{ v: number }> => ({ v: k }) as const;
|
|
6
6
|
|
|
7
7
|
// Test types for additional functionality
|
|
8
8
|
type TestElement = Readonly<{ id: number; type: string }>;
|
|
9
9
|
|
|
10
10
|
const testElementToString = (el: Readonly<TestElement>): string =>
|
|
11
|
-
`${el.type}_${el.id}
|
|
11
|
+
`${el.type}_${el.id}` as const;
|
|
12
12
|
|
|
13
13
|
const stringToTestElement = (str: string): TestElement => {
|
|
14
14
|
const [type, idStr] = str.split('_');
|
|
@@ -185,7 +185,7 @@ describe('ISetMapped.forEach', () => {
|
|
|
185
185
|
fromKey,
|
|
186
186
|
);
|
|
187
187
|
|
|
188
|
-
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
|
|
188
|
+
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
|
|
189
189
|
|
|
190
190
|
for (const el of s0) {
|
|
191
191
|
expect(elements).toContainEqual(el);
|
|
@@ -201,7 +201,7 @@ describe('ISetMapped.keys', () => {
|
|
|
201
201
|
fromKey,
|
|
202
202
|
);
|
|
203
203
|
|
|
204
|
-
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
|
|
204
|
+
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
|
|
205
205
|
|
|
206
206
|
for (const k of s0.keys()) {
|
|
207
207
|
expect(elements).toContainEqual(k);
|
|
@@ -217,7 +217,7 @@ describe('ISetMapped.values', () => {
|
|
|
217
217
|
fromKey,
|
|
218
218
|
);
|
|
219
219
|
|
|
220
|
-
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
|
|
220
|
+
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
|
|
221
221
|
|
|
222
222
|
for (const v of s0.values()) {
|
|
223
223
|
expect(elements).toContainEqual(v);
|
|
@@ -233,7 +233,7 @@ describe('ISetMapped.entries', () => {
|
|
|
233
233
|
fromKey,
|
|
234
234
|
);
|
|
235
235
|
|
|
236
|
-
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }];
|
|
236
|
+
const elements = [{ v: 1 }, { v: 2 }, { v: 3 }] as const;
|
|
237
237
|
|
|
238
238
|
for (const [k, v] of s0.entries()) {
|
|
239
239
|
expect(elements).toContainEqual(k);
|
package/src/collections/iset.mts
CHANGED
|
@@ -83,7 +83,9 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
|
|
|
83
83
|
// Reducing a value
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
* Checks if all elements in the set satisfy a predicate.
|
|
86
|
+
* Checks if all elements in the set satisfy a predicate. Also supports a
|
|
87
|
+
* type predicate overload that narrows the type of elements in the set if
|
|
88
|
+
* the predicate returns true for all elements.
|
|
87
89
|
*
|
|
88
90
|
* @example
|
|
89
91
|
*
|
|
@@ -101,19 +103,11 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
|
|
|
101
103
|
* assert.isTrue(narrowed);
|
|
102
104
|
* ```
|
|
103
105
|
*
|
|
106
|
+
* @template L The narrowed type of the elements.
|
|
104
107
|
* @param predicate A function to test each element.
|
|
105
108
|
* @returns `true` if all elements satisfy the predicate, `false` otherwise.
|
|
106
109
|
*/
|
|
107
110
|
every: ((predicate: (key: K) => boolean) => boolean) &
|
|
108
|
-
/**
|
|
109
|
-
* Checks if all elements in the set satisfy a type predicate. Narrows the
|
|
110
|
-
* type of elements in the set if the predicate returns true for all
|
|
111
|
-
* elements.
|
|
112
|
-
*
|
|
113
|
-
* @template L The narrowed type of the elements.
|
|
114
|
-
* @param predicate A type predicate function.
|
|
115
|
-
* @returns `true` if all elements satisfy the predicate, `false` otherwise.
|
|
116
|
-
*/
|
|
117
111
|
(<L extends K>(predicate: (key: K) => key is L) => this is ISet<L>);
|
|
118
112
|
|
|
119
113
|
/**
|
|
@@ -194,7 +188,7 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
|
|
|
194
188
|
* >[] = [
|
|
195
189
|
* { type: 'add', key: 'c' },
|
|
196
190
|
* { type: 'delete', key: 'a' },
|
|
197
|
-
* ];
|
|
191
|
+
* ] as const;
|
|
198
192
|
*
|
|
199
193
|
* const mutated = base.withMutations(actions);
|
|
200
194
|
*
|
|
@@ -234,8 +228,8 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
|
|
|
234
228
|
map: <K2 extends MapSetKeyType>(mapFn: (key: K) => K2) => ISet<K2>;
|
|
235
229
|
|
|
236
230
|
/**
|
|
237
|
-
* Filters the elements of the set based on a
|
|
238
|
-
* of elements in the resulting set.
|
|
231
|
+
* Filters the elements of the set based on a predicate. Also supports a type
|
|
232
|
+
* predicate overload that narrows the type of elements in the resulting set.
|
|
239
233
|
*
|
|
240
234
|
* @example
|
|
241
235
|
*
|
|
@@ -254,16 +248,10 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
|
|
|
254
248
|
* ```
|
|
255
249
|
*
|
|
256
250
|
* @template K2 The narrowed type of the elements.
|
|
257
|
-
* @param predicate A
|
|
258
|
-
* @returns A new ISet instance with elements that satisfy the
|
|
251
|
+
* @param predicate A function to test each element.
|
|
252
|
+
* @returns A new ISet instance with elements that satisfy the predicate.
|
|
259
253
|
*/
|
|
260
254
|
filter: (<K2 extends K>(predicate: (key: K) => key is K2) => ISet<K2>) &
|
|
261
|
-
/**
|
|
262
|
-
* Filters the elements of the set based on a predicate.
|
|
263
|
-
*
|
|
264
|
-
* @param predicate A function to test each element.
|
|
265
|
-
* @returns A new ISet instance with elements that satisfy the predicate.
|
|
266
|
-
*/
|
|
267
255
|
((predicate: (key: K) => boolean) => ISet<K>);
|
|
268
256
|
|
|
269
257
|
/**
|
|
@@ -637,10 +625,11 @@ export namespace ISet {
|
|
|
637
625
|
export const diff = <K extends MapSetKeyType>(
|
|
638
626
|
oldSet: ISet<K>,
|
|
639
627
|
newSet: ISet<K>,
|
|
640
|
-
): ReadonlyRecord<'added' | 'deleted', ISet<K>> =>
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
628
|
+
): ReadonlyRecord<'added' | 'deleted', ISet<K>> =>
|
|
629
|
+
({
|
|
630
|
+
deleted: oldSet.subtract(newSet),
|
|
631
|
+
added: newSet.subtract(oldSet),
|
|
632
|
+
}) as const;
|
|
644
633
|
|
|
645
634
|
/**
|
|
646
635
|
* Computes the intersection of two ISet instances.
|
|
@@ -585,7 +585,8 @@ describe('Queue test', () => {
|
|
|
585
585
|
// Perform 1000 random operations
|
|
586
586
|
for (const _i of range(asUint32(1000))) {
|
|
587
587
|
// Randomly decide to enqueue or dequeue
|
|
588
|
-
const shouldEnqueue =
|
|
588
|
+
const shouldEnqueue =
|
|
589
|
+
Arr.isArrayOfLength(mut_expected, 0) || Math.random() < 0.6;
|
|
589
590
|
|
|
590
591
|
if (shouldEnqueue) {
|
|
591
592
|
mut_counter += 1;
|
|
@@ -153,9 +153,9 @@ describe('Stack test', () => {
|
|
|
153
153
|
|
|
154
154
|
const stack = createStack<Item>();
|
|
155
155
|
|
|
156
|
-
const item1: Item = { id: 1, name: 'first' };
|
|
156
|
+
const item1: Item = { id: 1, name: 'first' } as const;
|
|
157
157
|
|
|
158
|
-
const item2: Item = { id: 2, name: 'second' };
|
|
158
|
+
const item2: Item = { id: 2, name: 'second' } as const;
|
|
159
159
|
|
|
160
160
|
stack.push(item1);
|
|
161
161
|
|
|
@@ -198,7 +198,7 @@ describe('Stack test', () => {
|
|
|
198
198
|
});
|
|
199
199
|
|
|
200
200
|
test('should not mutate initial values array', () => {
|
|
201
|
-
const initialValues = [1, 2, 3];
|
|
201
|
+
const initialValues = [1, 2, 3] as readonly number[];
|
|
202
202
|
|
|
203
203
|
const originalLength = initialValues.length;
|
|
204
204
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isRecord } from '../../../guard/index.mjs';
|
|
1
|
+
import { hasKey, isRecord } from '../../../guard/index.mjs';
|
|
2
2
|
import { NoneTypeTagName, SomeTypeTagName } from './tag.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -9,7 +9,7 @@ import { NoneTypeTagName, SomeTypeTagName } from './tag.mjs';
|
|
|
9
9
|
* ```ts
|
|
10
10
|
* const maybeOptional = Optional.some('value');
|
|
11
11
|
*
|
|
12
|
-
* const notOptional = { $$tag: 'ts-data-forge::Optional.some' };
|
|
12
|
+
* const notOptional = { $$tag: 'ts-data-forge::Optional.some' } as const;
|
|
13
13
|
*
|
|
14
14
|
* assert.isTrue(Optional.isOptional(maybeOptional));
|
|
15
15
|
*
|
|
@@ -23,7 +23,7 @@ export const isOptional = (
|
|
|
23
23
|
maybeOptional: unknown,
|
|
24
24
|
): maybeOptional is Optional<unknown> =>
|
|
25
25
|
isRecord(maybeOptional) &&
|
|
26
|
-
|
|
27
|
-
((maybeOptional
|
|
28
|
-
|
|
29
|
-
maybeOptional
|
|
26
|
+
hasKey(maybeOptional, '$$tag') &&
|
|
27
|
+
((maybeOptional.$$tag === SomeTypeTagName &&
|
|
28
|
+
hasKey(maybeOptional, 'value')) ||
|
|
29
|
+
maybeOptional.$$tag === NoneTypeTagName);
|
|
@@ -19,7 +19,8 @@ import { SomeTypeTagName } from './tag.mjs';
|
|
|
19
19
|
* @param value The value to wrap in an {@link Some}.
|
|
20
20
|
* @returns An {@link Some}<S> containing the value.
|
|
21
21
|
*/
|
|
22
|
-
export const some = <const S,>(value: S): Some<S> =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
export const some = <const S,>(value: S): Some<S> =>
|
|
23
|
+
({
|
|
24
|
+
$$tag: SomeTypeTagName,
|
|
25
|
+
value,
|
|
26
|
+
}) as const;
|
|
@@ -14,7 +14,7 @@ import { some } from './optional-some.mjs';
|
|
|
14
14
|
* assert.isTrue(Optional.isSome(zipped));
|
|
15
15
|
*
|
|
16
16
|
* if (Optional.isSome(zipped)) {
|
|
17
|
-
* const expected: readonly [string, number] = ['left', 1];
|
|
17
|
+
* const expected: readonly [string, number] = ['left', 1] as const;
|
|
18
18
|
*
|
|
19
19
|
* assert.deepStrictEqual(zipped.value, expected);
|
|
20
20
|
* }
|
|
@@ -25,7 +25,8 @@ import { ErrTypeTagName } from './tag.mjs';
|
|
|
25
25
|
* @param value The error value.
|
|
26
26
|
* @returns A `Result.Err<E>` containing the value.
|
|
27
27
|
*/
|
|
28
|
-
export const err = <const E,>(value: E): Err<E> =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
export const err = <const E,>(value: E): Err<E> =>
|
|
29
|
+
({
|
|
30
|
+
$$tag: ErrTypeTagName,
|
|
31
|
+
value,
|
|
32
|
+
}) as const;
|
|
@@ -11,7 +11,7 @@ import { ErrTypeTagName, OkTypeTagName } from './tag.mjs';
|
|
|
11
11
|
*
|
|
12
12
|
* const errValue = Result.err(new Error('failure'));
|
|
13
13
|
*
|
|
14
|
-
* const notResult = { $$tag: 'ts-data-forge::Result.ok' };
|
|
14
|
+
* const notResult = { $$tag: 'ts-data-forge::Result.ok' } as const;
|
|
15
15
|
*
|
|
16
16
|
* assert.isTrue(Result.isResult(okValue));
|
|
17
17
|
*
|
|
@@ -25,7 +25,8 @@ import { OkTypeTagName } from './tag.mjs';
|
|
|
25
25
|
* @param value The success value.
|
|
26
26
|
* @returns A `Result.Ok<S>` containing the value.
|
|
27
27
|
*/
|
|
28
|
-
export const ok = <const S,>(value: S): Ok<S> =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
export const ok = <const S,>(value: S): Ok<S> =>
|
|
29
|
+
({
|
|
30
|
+
$$tag: OkTypeTagName,
|
|
31
|
+
value,
|
|
32
|
+
}) as const;
|
|
@@ -821,7 +821,7 @@ describe('Result test', () => {
|
|
|
821
821
|
});
|
|
822
822
|
|
|
823
823
|
test('should return Ok with object when function succeeds', () => {
|
|
824
|
-
const obj = { name: 'test', value: 123 };
|
|
824
|
+
const obj = { name: 'test', value: 123 } as const;
|
|
825
825
|
|
|
826
826
|
const result = Result.fromThrowable(() => obj);
|
|
827
827
|
|
|
@@ -901,7 +901,7 @@ describe('Result test', () => {
|
|
|
901
901
|
});
|
|
902
902
|
|
|
903
903
|
test('should work with array access', () => {
|
|
904
|
-
const arr = [1, 2, 3];
|
|
904
|
+
const arr = [1, 2, 3] as readonly number[];
|
|
905
905
|
|
|
906
906
|
// This won't throw, but demonstrates the pattern
|
|
907
907
|
const result = Result.fromThrowable(() => {
|
|
@@ -13,7 +13,8 @@ import { ErrTypeTagName } from './tag.mjs';
|
|
|
13
13
|
* assert.isTrue(TernaryResult.isErr(failure));
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
export const err = <const E,>(value: E): TernaryErr<E> =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
export const err = <const E,>(value: E): TernaryErr<E> =>
|
|
17
|
+
({
|
|
18
|
+
$$tag: ErrTypeTagName,
|
|
19
|
+
value,
|
|
20
|
+
}) as const;
|
|
@@ -11,7 +11,7 @@ import { ErrTypeTagName, OkTypeTagName, WarnTypeTagName } from './tag.mjs';
|
|
|
11
11
|
*
|
|
12
12
|
* const warnValue = TernaryResult.warn('done', 'retry later');
|
|
13
13
|
*
|
|
14
|
-
* const notResult = { $$tag: 'ts-data-forge::Result.ok' };
|
|
14
|
+
* const notResult = { $$tag: 'ts-data-forge::Result.ok' } as const;
|
|
15
15
|
*
|
|
16
16
|
* assert.isTrue(TernaryResult.isTernaryResult(okValue));
|
|
17
17
|
*
|
|
@@ -14,7 +14,8 @@ import { OkTypeTagName } from './tag.mjs';
|
|
|
14
14
|
* });
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
export const ok = <const S,>(value: S): TernaryOk<S> =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
export const ok = <const S,>(value: S): TernaryOk<S> =>
|
|
18
|
+
({
|
|
19
|
+
$$tag: OkTypeTagName,
|
|
20
|
+
value,
|
|
21
|
+
}) as const;
|
|
@@ -19,8 +19,9 @@ import { WarnTypeTagName } from './tag.mjs';
|
|
|
19
19
|
export const warn = <const S, const W>(
|
|
20
20
|
value: S,
|
|
21
21
|
warning: W,
|
|
22
|
-
): TernaryWarn<S, W> =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
): TernaryWarn<S, W> =>
|
|
23
|
+
({
|
|
24
|
+
$$tag: WarnTypeTagName,
|
|
25
|
+
value,
|
|
26
|
+
warning,
|
|
27
|
+
}) as const;
|
package/src/guard/has-key.mts
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
* @example
|
|
18
18
|
*
|
|
19
19
|
* ```ts
|
|
20
|
-
* const maybeUser: Readonly<{ id?: number; name?: string }> = {
|
|
20
|
+
* const maybeUser: Readonly<{ id?: number; name?: string }> = {
|
|
21
|
+
* id: 42,
|
|
22
|
+
* } as const;
|
|
21
23
|
*
|
|
22
24
|
* if (hasKey(maybeUser, 'id')) {
|
|
23
25
|
* // `maybeUser` is now known to have an `id` property.
|
|
@@ -43,7 +45,9 @@ export const hasKey = <
|
|
|
43
45
|
>(
|
|
44
46
|
obj: R,
|
|
45
47
|
key: K,
|
|
46
|
-
): obj is HasKeyReturnType<R, K> =>
|
|
48
|
+
): obj is HasKeyReturnType<R, K> =>
|
|
49
|
+
// eslint-disable-next-line ts-data-forge/prefer-is-record-and-has-key
|
|
50
|
+
Object.hasOwn(obj, key);
|
|
47
51
|
|
|
48
52
|
/**
|
|
49
53
|
* @internal
|
|
@@ -73,7 +73,7 @@ describe(isNonNullObject, () => {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
test('should act as a type guard', () => {
|
|
76
|
-
const value: unknown = { test: true };
|
|
76
|
+
const value: unknown = { test: true } as const;
|
|
77
77
|
|
|
78
78
|
if (isNonNullObject(value)) {
|
|
79
79
|
expectType<typeof value, object>('=');
|
|
@@ -81,7 +81,8 @@ describe(isNonNullObject, () => {
|
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
test('should narrow nullable object types', () => {
|
|
84
|
-
const nullable: UnknownRecord | null =
|
|
84
|
+
const nullable: UnknownRecord | null =
|
|
85
|
+
Math.random() > 0.5 ? ({} as const) : null;
|
|
85
86
|
|
|
86
87
|
if (isNonNullObject(nullable)) {
|
|
87
88
|
expectType<typeof nullable, UnknownRecord>('=');
|
|
@@ -98,7 +99,7 @@ describe(isNonNullObject, () => {
|
|
|
98
99
|
[],
|
|
99
100
|
() => {},
|
|
100
101
|
true,
|
|
101
|
-
];
|
|
102
|
+
] as const;
|
|
102
103
|
|
|
103
104
|
const objects = mixed.filter(isNonNullObject);
|
|
104
105
|
|
package/src/guard/is-record.mts
CHANGED
|
@@ -25,7 +25,7 @@ import { isNonNullObject } from './is-non-null-object.mjs';
|
|
|
25
25
|
* @example
|
|
26
26
|
*
|
|
27
27
|
* ```ts
|
|
28
|
-
* const entries: readonly unknown[] = [{ id: 1 }, 'str', 0, null];
|
|
28
|
+
* const entries: readonly unknown[] = [{ id: 1 }, 'str', 0, null] as const;
|
|
29
29
|
*
|
|
30
30
|
* const records = entries.filter(isRecord);
|
|
31
31
|
*
|
|
@@ -58,7 +58,7 @@ export const isRecord = (u: unknown): u is UnknownRecord => isNonNullObject(u);
|
|
|
58
58
|
*
|
|
59
59
|
* @example
|
|
60
60
|
* ```ts
|
|
61
|
-
* const obj: unknown = { foo: 1 };
|
|
61
|
+
* const obj: unknown = { foo: 1 } as const;
|
|
62
62
|
*
|
|
63
63
|
* if (isMutableRecord(obj)) {
|
|
64
64
|
* obj['bar'] = 2; // Safe: obj is now known to be a mutable record
|
|
@@ -4,7 +4,7 @@ import { isRecord } from './is-record.mjs';
|
|
|
4
4
|
describe(isRecord, () => {
|
|
5
5
|
describe('arrays are Records', () => {
|
|
6
6
|
test('number[] is assignable to Record<number, unknown>', () => {
|
|
7
|
-
const arr: Record<number, unknown> = [1, 2, 3];
|
|
7
|
+
const arr: Record<number, unknown> = [1, 2, 3] as const;
|
|
8
8
|
|
|
9
9
|
const unk: unknown = arr;
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ describe(isRecord, () => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
test('string[] is assignable to Record<number, unknown>', () => {
|
|
17
|
-
const arr: Record<number, unknown> = ['1', '2', '3'];
|
|
17
|
+
const arr: Record<number, unknown> = ['1', '2', '3'] as const;
|
|
18
18
|
|
|
19
19
|
const unk: unknown = arr;
|
|
20
20
|
|
package/src/guard/is-type.mts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @example
|
|
10
10
|
*
|
|
11
11
|
* ```ts
|
|
12
|
-
* const values: readonly (number | undefined)[] = [1, undefined, 2];
|
|
12
|
+
* const values: readonly (number | undefined)[] = [1, undefined, 2] as const;
|
|
13
13
|
*
|
|
14
14
|
* const undefinedValues = values.filter(isUndefined);
|
|
15
15
|
*
|
|
@@ -34,7 +34,7 @@ export const isUndefined = (u: unknown): u is undefined => u === undefined;
|
|
|
34
34
|
* @example
|
|
35
35
|
*
|
|
36
36
|
* ```ts
|
|
37
|
-
* const values: readonly (number | undefined)[] = [1, undefined, 2];
|
|
37
|
+
* const values: readonly (number | undefined)[] = [1, undefined, 2] as const;
|
|
38
38
|
*
|
|
39
39
|
* const definedValues = values.filter(isNotUndefined);
|
|
40
40
|
*
|
|
@@ -60,7 +60,7 @@ export const isNotUndefined = <T,>(u: T): u is RelaxedExclude<T, undefined> =>
|
|
|
60
60
|
* @example
|
|
61
61
|
*
|
|
62
62
|
* ```ts
|
|
63
|
-
* const flags: readonly unknown[] = [true, 'no', false];
|
|
63
|
+
* const flags: readonly unknown[] = [true, 'no', false] as const;
|
|
64
64
|
*
|
|
65
65
|
* const booleans = flags.filter(isBoolean);
|
|
66
66
|
*
|
|
@@ -84,7 +84,7 @@ export const isBoolean = (u: unknown): u is boolean => typeof u === 'boolean';
|
|
|
84
84
|
* @example
|
|
85
85
|
*
|
|
86
86
|
* ```ts
|
|
87
|
-
* const flags: readonly unknown[] = [true, 'no', false];
|
|
87
|
+
* const flags: readonly unknown[] = [true, 'no', false] as const;
|
|
88
88
|
*
|
|
89
89
|
* const nonBooleans = flags.filter(isNotBoolean);
|
|
90
90
|
*
|
|
@@ -111,7 +111,7 @@ export const isNotBoolean = <T,>(u: T): u is RelaxedExclude<T, boolean> =>
|
|
|
111
111
|
* @example
|
|
112
112
|
*
|
|
113
113
|
* ```ts
|
|
114
|
-
* const mixed: readonly unknown[] = [1, '2', 3];
|
|
114
|
+
* const mixed: readonly unknown[] = [1, '2', 3] as const;
|
|
115
115
|
*
|
|
116
116
|
* const numbers = mixed.filter(isNumber);
|
|
117
117
|
*
|
|
@@ -135,7 +135,7 @@ export const isNumber = (u: unknown): u is number => typeof u === 'number';
|
|
|
135
135
|
* @example
|
|
136
136
|
*
|
|
137
137
|
* ```ts
|
|
138
|
-
* const mixed: readonly unknown[] = [1, '2', 3];
|
|
138
|
+
* const mixed: readonly unknown[] = [1, '2', 3] as const;
|
|
139
139
|
*
|
|
140
140
|
* const nonNumbers = mixed.filter(isNotNumber);
|
|
141
141
|
*
|
|
@@ -161,7 +161,7 @@ export const isNotNumber = <T,>(u: T): u is RelaxedExclude<T, number> =>
|
|
|
161
161
|
* @example
|
|
162
162
|
*
|
|
163
163
|
* ```ts
|
|
164
|
-
* const values: readonly unknown[] = [1n, 2, 3n];
|
|
164
|
+
* const values: readonly unknown[] = [1n, 2, 3n] as const;
|
|
165
165
|
*
|
|
166
166
|
* const bigints = values.filter(isBigint);
|
|
167
167
|
*
|
|
@@ -185,7 +185,7 @@ export const isBigint = (u: unknown): u is bigint => typeof u === 'bigint';
|
|
|
185
185
|
* @example
|
|
186
186
|
*
|
|
187
187
|
* ```ts
|
|
188
|
-
* const values: readonly unknown[] = [1n, 2, 3n];
|
|
188
|
+
* const values: readonly unknown[] = [1n, 2, 3n] as const;
|
|
189
189
|
*
|
|
190
190
|
* const nonBigints = values.filter(isNotBigint);
|
|
191
191
|
*
|
|
@@ -212,7 +212,7 @@ export const isNotBigint = <T,>(u: T): u is RelaxedExclude<T, bigint> =>
|
|
|
212
212
|
* @example
|
|
213
213
|
*
|
|
214
214
|
* ```ts
|
|
215
|
-
* const values: readonly unknown[] = ['Ada', 42, 'Lovelace'];
|
|
215
|
+
* const values: readonly unknown[] = ['Ada', 42, 'Lovelace'] as const;
|
|
216
216
|
*
|
|
217
217
|
* const strings = values.filter(isString);
|
|
218
218
|
*
|
|
@@ -236,7 +236,7 @@ export const isString = (u: unknown): u is string => typeof u === 'string';
|
|
|
236
236
|
* @example
|
|
237
237
|
*
|
|
238
238
|
* ```ts
|
|
239
|
-
* const values: readonly unknown[] = ['Ada', 42, 'Lovelace'];
|
|
239
|
+
* const values: readonly unknown[] = ['Ada', 42, 'Lovelace'] as const;
|
|
240
240
|
*
|
|
241
241
|
* const nonStrings = values.filter(isNotString);
|
|
242
242
|
*
|
|
@@ -266,7 +266,7 @@ export const isNotString = <T,>(u: T): u is RelaxedExclude<T, string> =>
|
|
|
266
266
|
*
|
|
267
267
|
* const shared = Symbol.for('shared');
|
|
268
268
|
*
|
|
269
|
-
* const tokens: readonly unknown[] = [id, 'shared', shared];
|
|
269
|
+
* const tokens: readonly unknown[] = [id, 'shared', shared] as const;
|
|
270
270
|
*
|
|
271
271
|
* const symbols = tokens.filter(isSymbol);
|
|
272
272
|
*
|
|
@@ -292,7 +292,7 @@ export const isSymbol = (u: unknown): u is symbol => typeof u === 'symbol';
|
|
|
292
292
|
* ```ts
|
|
293
293
|
* const id = Symbol('id');
|
|
294
294
|
*
|
|
295
|
-
* const tokens: readonly unknown[] = [id, 'shared'];
|
|
295
|
+
* const tokens: readonly unknown[] = [id, 'shared'] as const;
|
|
296
296
|
*
|
|
297
297
|
* const nonSymbols = tokens.filter(isNotSymbol);
|
|
298
298
|
*
|
|
@@ -343,7 +343,7 @@ export const isNull = (u: unknown): u is null => u === null;
|
|
|
343
343
|
* @example
|
|
344
344
|
*
|
|
345
345
|
* ```ts
|
|
346
|
-
* const values: readonly (number | null)[] = [null, 5];
|
|
346
|
+
* const values: readonly (number | null)[] = [null, 5] as const;
|
|
347
347
|
*
|
|
348
348
|
* const nonNullValues = values.filter(isNotNull);
|
|
349
349
|
*
|
|
@@ -376,7 +376,7 @@ export const isNotNull = <T,>(u: T | null): u is T => u !== null;
|
|
|
376
376
|
* 'Ada',
|
|
377
377
|
* null,
|
|
378
378
|
* undefined,
|
|
379
|
-
* ];
|
|
379
|
+
* ] as const;
|
|
380
380
|
*
|
|
381
381
|
* const nullishValues = values.filter(isNullish);
|
|
382
382
|
*
|
|
@@ -409,7 +409,7 @@ export const isNullish = (u: unknown): u is null | undefined => u == null;
|
|
|
409
409
|
* 'Ada',
|
|
410
410
|
* null,
|
|
411
411
|
* undefined,
|
|
412
|
-
* ];
|
|
412
|
+
* ] as const;
|
|
413
413
|
*
|
|
414
414
|
* const definedValues = values.filter(isNonNullish);
|
|
415
415
|
*
|
|
@@ -572,7 +572,7 @@ describe(isNonNullish, () => {
|
|
|
572
572
|
'world',
|
|
573
573
|
undefined,
|
|
574
574
|
'test',
|
|
575
|
-
];
|
|
575
|
+
] as const;
|
|
576
576
|
|
|
577
577
|
const definedItems = items.filter(isNonNullish);
|
|
578
578
|
|
|
@@ -618,7 +618,7 @@ describe('type guard behavior in complex scenarios', () => {
|
|
|
618
618
|
undefined,
|
|
619
619
|
false,
|
|
620
620
|
123,
|
|
621
|
-
];
|
|
621
|
+
] as const;
|
|
622
622
|
|
|
623
623
|
const nonNullish = mixed.filter(isNonNullish);
|
|
624
624
|
|
package/src/guard/key-is-in.mts
CHANGED
package/src/json/json.mts
CHANGED
|
@@ -93,7 +93,7 @@ export namespace Json {
|
|
|
93
93
|
* @example
|
|
94
94
|
*
|
|
95
95
|
* ```ts
|
|
96
|
-
* const data = { name: 'Bob', age: 25, active: true };
|
|
96
|
+
* const data = { name: 'Bob', age: 25, active: true } as const;
|
|
97
97
|
*
|
|
98
98
|
* // Basic stringify
|
|
99
99
|
* const basic = Json.stringify(data);
|
|
@@ -177,7 +177,7 @@ export namespace Json {
|
|
|
177
177
|
* email: 'charlie@example.com',
|
|
178
178
|
* password: 'secret123',
|
|
179
179
|
* role: 'admin',
|
|
180
|
-
* };
|
|
180
|
+
* } as const;
|
|
181
181
|
*
|
|
182
182
|
* // Select only safe properties to serialize
|
|
183
183
|
* const safeJson = Json.stringifySelected(user, ['id', 'name', 'role']);
|
|
@@ -262,7 +262,7 @@ export namespace Json {
|
|
|
262
262
|
* alpha: 'a',
|
|
263
263
|
* beta: 'b',
|
|
264
264
|
* },
|
|
265
|
-
* };
|
|
265
|
+
* } as const;
|
|
266
266
|
*
|
|
267
267
|
* // Keys will be sorted alphabetically at all levels
|
|
268
268
|
* const sorted = Json.stringifySortedKey(unorderedData);
|
|
@@ -354,6 +354,7 @@ const keysDeepImpl = (
|
|
|
354
354
|
keysDeepImpl(o, mut_keys);
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
+
// eslint-disable-next-line ts-data-forge/prefer-arr-is-array
|
|
357
358
|
if (Array.isArray(o)) {
|
|
358
359
|
for (const li of o) {
|
|
359
360
|
if (isRecord(li)) {
|