ts-data-forge 2.1.1 → 2.1.3

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.
Files changed (103) hide show
  1. package/README.md +13 -15
  2. package/dist/array/array-utils.d.mts.map +1 -1
  3. package/dist/array/array-utils.mjs +9 -13
  4. package/dist/array/array-utils.mjs.map +1 -1
  5. package/dist/collections/imap.d.mts +1 -1
  6. package/dist/collections/imap.d.mts.map +1 -1
  7. package/dist/collections/imap.mjs +5 -5
  8. package/dist/collections/imap.mjs.map +1 -1
  9. package/dist/collections/iset-mapped.d.mts +1 -1
  10. package/dist/collections/iset-mapped.mjs +1 -1
  11. package/dist/collections/iset.d.mts +2 -2
  12. package/dist/collections/iset.mjs +4 -5
  13. package/dist/collections/iset.mjs.map +1 -1
  14. package/dist/collections/queue.d.mts +1 -1
  15. package/dist/collections/queue.d.mts.map +1 -1
  16. package/dist/collections/queue.mjs +7 -8
  17. package/dist/collections/queue.mjs.map +1 -1
  18. package/dist/collections/stack.d.mts +1 -1
  19. package/dist/collections/stack.d.mts.map +1 -1
  20. package/dist/collections/stack.mjs +6 -7
  21. package/dist/collections/stack.mjs.map +1 -1
  22. package/dist/entry-point.d.mts.map +1 -1
  23. package/dist/functional/match.d.mts.map +1 -1
  24. package/dist/functional/match.mjs +1 -6
  25. package/dist/functional/match.mjs.map +1 -1
  26. package/dist/functional/optional.d.mts.map +1 -1
  27. package/dist/functional/optional.mjs +6 -4
  28. package/dist/functional/optional.mjs.map +1 -1
  29. package/dist/functional/result.d.mts.map +1 -1
  30. package/dist/functional/result.mjs +1 -6
  31. package/dist/functional/result.mjs.map +1 -1
  32. package/dist/json/json.d.mts.map +1 -1
  33. package/dist/json/json.mjs +3 -3
  34. package/dist/json/json.mjs.map +1 -1
  35. package/dist/others/memoize-function.d.mts +1 -1
  36. package/dist/others/memoize-function.mjs +1 -1
  37. package/dist/others/unknown-to-string.d.mts +44 -77
  38. package/dist/others/unknown-to-string.d.mts.map +1 -1
  39. package/dist/others/unknown-to-string.mjs +51 -85
  40. package/dist/others/unknown-to-string.mjs.map +1 -1
  41. package/package.json +10 -1
  42. package/src/array/array-utils-creation.test.mts +9 -8
  43. package/src/array/array-utils-overload-type-error.test.mts +6 -2
  44. package/src/array/array-utils-search.test.mts +1 -1
  45. package/src/array/array-utils-slicing.test.mts +0 -42
  46. package/src/array/array-utils-transformation.test.mts +11 -186
  47. package/src/array/array-utils-validation.test.mts +27 -27
  48. package/src/array/array-utils.mts +8 -12
  49. package/src/collections/imap-mapped.test.mts +15 -11
  50. package/src/collections/imap.mts +6 -13
  51. package/src/collections/imap.test.mts +20 -19
  52. package/src/collections/iset-mapped.mts +1 -1
  53. package/src/collections/iset-mapped.test.mts +14 -104
  54. package/src/collections/iset.mts +5 -7
  55. package/src/collections/iset.test.mts +43 -34
  56. package/src/collections/queue.mts +12 -10
  57. package/src/collections/queue.test.mts +46 -44
  58. package/src/collections/stack.mts +10 -9
  59. package/src/collections/stack.test.mts +12 -10
  60. package/src/entry-point.mts +1 -0
  61. package/src/functional/match.mts +1 -5
  62. package/src/functional/optional.mts +6 -6
  63. package/src/functional/optional.test.mts +7 -7
  64. package/src/functional/result.mts +1 -5
  65. package/src/guard/is-non-empty-string.test.mts +1 -1
  66. package/src/guard/is-non-null-object.test.mts +3 -3
  67. package/src/guard/is-primitive.test.mts +6 -6
  68. package/src/guard/is-type.test.mts +8 -12
  69. package/src/iterator/range.test.mts +1 -1
  70. package/src/json/json.mts +4 -11
  71. package/src/json/json.test.mts +25 -28
  72. package/src/number/branded-types/finite-number.test.mts +2 -1
  73. package/src/number/branded-types/int.test.mts +2 -1
  74. package/src/number/branded-types/int16.test.mts +3 -2
  75. package/src/number/branded-types/int32.test.mts +3 -2
  76. package/src/number/branded-types/non-negative-finite-number.test.mts +3 -2
  77. package/src/number/branded-types/non-negative-int16.test.mts +3 -2
  78. package/src/number/branded-types/non-negative-int32.test.mts +3 -2
  79. package/src/number/branded-types/non-zero-finite-number.test.mts +4 -3
  80. package/src/number/branded-types/non-zero-int.test.mts +4 -3
  81. package/src/number/branded-types/non-zero-int16.test.mts +3 -2
  82. package/src/number/branded-types/non-zero-int32.test.mts +3 -2
  83. package/src/number/branded-types/non-zero-safe-int.test.mts +4 -3
  84. package/src/number/branded-types/non-zero-uint16.test.mts +3 -2
  85. package/src/number/branded-types/non-zero-uint32.test.mts +3 -2
  86. package/src/number/branded-types/positive-finite-number.test.mts +3 -2
  87. package/src/number/branded-types/positive-int.test.mts +3 -2
  88. package/src/number/branded-types/positive-int16.test.mts +3 -2
  89. package/src/number/branded-types/positive-int32.test.mts +3 -2
  90. package/src/number/branded-types/positive-safe-int.test.mts +3 -2
  91. package/src/number/branded-types/positive-uint16.test.mts +3 -2
  92. package/src/number/branded-types/positive-uint32.test.mts +3 -2
  93. package/src/number/branded-types/safe-int.test.mts +3 -2
  94. package/src/number/branded-types/safe-uint.test.mts +3 -2
  95. package/src/number/branded-types/uint.test.mts +3 -2
  96. package/src/number/branded-types/uint16.test.mts +3 -2
  97. package/src/number/branded-types/uint32.test.mts +3 -2
  98. package/src/object/object.test.mts +10 -10
  99. package/src/others/cast-readonly.test.mts +8 -8
  100. package/src/others/memoize-function.mts +1 -1
  101. package/src/others/memoize-function.test.mts +2 -2
  102. package/src/others/unknown-to-string.mts +52 -87
  103. package/src/others/unknown-to-string.test.mts +26 -58
@@ -1,4 +1,5 @@
1
1
  import { expectType } from '../../expect-type.mjs';
2
+ import { range } from '../../iterator/index.mjs';
2
3
  import { asSafeInt, SafeInt } from './safe-int.mjs';
3
4
 
4
5
  describe('SafeInt', () => {
@@ -142,7 +143,7 @@ describe('SafeInt', () => {
142
143
  const min = -20;
143
144
  const max = 20;
144
145
 
145
- for (let i = 0; i < 10; i++) {
146
+ for (const _ of range(10)) {
146
147
  const result = SafeInt.random(min, max);
147
148
  expect(result).toBeGreaterThanOrEqual(min);
148
149
  expect(result).toBeLessThanOrEqual(max);
@@ -152,7 +153,7 @@ describe('SafeInt', () => {
152
153
  });
153
154
 
154
155
  test('generates values within safe integer range', () => {
155
- for (let i = 0; i < 10; i++) {
156
+ for (const _ of range(10)) {
156
157
  const result = SafeInt.random(-30, 30);
157
158
  expect(result).toBeGreaterThanOrEqual(Number.MIN_SAFE_INTEGER);
158
159
  expect(result).toBeLessThanOrEqual(Number.MAX_SAFE_INTEGER);
@@ -1,4 +1,5 @@
1
1
  import { expectType } from '../../expect-type.mjs';
2
+ import { range } from '../../iterator/index.mjs';
2
3
  import { asSafeUint, isSafeUint, SafeUint } from './safe-uint.mjs';
3
4
 
4
5
  describe('SafeUint', () => {
@@ -147,7 +148,7 @@ describe('SafeUint', () => {
147
148
  const min = 0;
148
149
  const max = 20;
149
150
 
150
- for (let i = 0; i < 10; i++) {
151
+ for (const _ of range(10)) {
151
152
  const result = SafeUint.random(min, max);
152
153
  expect(result).toBeGreaterThanOrEqual(min);
153
154
  expect(result).toBeLessThanOrEqual(max);
@@ -158,7 +159,7 @@ describe('SafeUint', () => {
158
159
  });
159
160
 
160
161
  test('generates values within safe uint range', () => {
161
- for (let i = 0; i < 10; i++) {
162
+ for (const _ of range(10)) {
162
163
  const result = SafeUint.random(0, 30);
163
164
  expect(result).toBeGreaterThanOrEqual(0);
164
165
  expect(result).toBeLessThanOrEqual(Number.MAX_SAFE_INTEGER);
@@ -1,4 +1,5 @@
1
1
  import { expectType } from '../../expect-type.mjs';
2
+ import { range } from '../../iterator/index.mjs';
2
3
  import { asUint, isUint, Uint } from './uint.mjs';
3
4
 
4
5
  describe('Uint', () => {
@@ -129,7 +130,7 @@ describe('Uint', () => {
129
130
  const min = 0;
130
131
  const max = 20;
131
132
 
132
- for (let i = 0; i < 10; i++) {
133
+ for (const _ of range(10)) {
133
134
  const result = Uint.random(min, max);
134
135
  expect(result).toBeGreaterThanOrEqual(min);
135
136
  expect(result).toBeLessThanOrEqual(max);
@@ -140,7 +141,7 @@ describe('Uint', () => {
140
141
  });
141
142
 
142
143
  test('generates values starting from 0', () => {
143
- for (let i = 0; i < 10; i++) {
144
+ for (const _ of range(10)) {
144
145
  const result = Uint.random(0, 30);
145
146
  expect(result).toBeGreaterThanOrEqual(0);
146
147
  expect(result).toBeLessThanOrEqual(30);
@@ -1,4 +1,5 @@
1
1
  import { expectType } from '../../expect-type.mjs';
2
+ import { range } from '../../iterator/index.mjs';
2
3
  import { asNonZeroUint16 } from './non-zero-uint16.mjs';
3
4
  import { asUint16, isUint16, Uint16 } from './uint16.mjs';
4
5
 
@@ -141,7 +142,7 @@ describe('Uint16', () => {
141
142
  const min = 0;
142
143
  const max = 20;
143
144
 
144
- for (let i = 0; i < 10; i++) {
145
+ for (const _ of range(10)) {
145
146
  const result = Uint16.random(min, max);
146
147
  expect(result).toBeGreaterThanOrEqual(min);
147
148
  expect(result).toBeLessThanOrEqual(max);
@@ -152,7 +153,7 @@ describe('Uint16', () => {
152
153
  });
153
154
 
154
155
  test('generates values within Uint16 range', () => {
155
- for (let i = 0; i < 10; i++) {
156
+ for (const _ of range(10)) {
156
157
  const result = Uint16.random(0, 30);
157
158
  expect(result).toBeGreaterThanOrEqual(0);
158
159
  expect(result).toBeLessThanOrEqual(65535);
@@ -1,4 +1,5 @@
1
1
  import { expectType } from '../../expect-type.mjs';
2
+ import { range } from '../../iterator/index.mjs';
2
3
  import { asNonZeroUint32 } from './non-zero-uint32.mjs';
3
4
  import { asUint32, isUint32, Uint32 } from './uint32.mjs';
4
5
 
@@ -141,7 +142,7 @@ describe('Uint32', () => {
141
142
  const min = 0;
142
143
  const max = 20;
143
144
 
144
- for (let i = 0; i < 10; i++) {
145
+ for (const _ of range(10)) {
145
146
  const result = Uint32.random(min, max);
146
147
  expect(result).toBeGreaterThanOrEqual(min);
147
148
  expect(result).toBeLessThanOrEqual(max);
@@ -152,7 +153,7 @@ describe('Uint32', () => {
152
153
  });
153
154
 
154
155
  test('generates values within Uint32 range', () => {
155
- for (let i = 0; i < 10; i++) {
156
+ for (const _ of range(10)) {
156
157
  const result = Uint32.random(0, 30);
157
158
  expect(result).toBeGreaterThanOrEqual(0);
158
159
  expect(result).toBeLessThanOrEqual(4294967295);
@@ -28,20 +28,20 @@ describe('shallowEq', () => {
28
28
  });
29
29
 
30
30
  describe('pick', () => {
31
- test('truthy case 1', () => {
31
+ test('should pick specified keys', () => {
32
32
  expect(Obj.pick({ a: 1, b: 2, c: 3 }, ['a', 'b'])).toStrictEqual({
33
33
  a: 1,
34
34
  b: 2,
35
35
  });
36
36
  });
37
37
 
38
- test('should support curried form', () => {
38
+ test('pick should support curried form', () => {
39
39
  const pickAB = Obj.pick(['a', 'b']);
40
40
  const result = pickAB({ a: 1, b: 2, c: 3, d: 4 });
41
41
  expect(result).toStrictEqual({ a: 1, b: 2 });
42
42
  });
43
43
 
44
- test('should work with pipe when curried', () => {
44
+ test('pick should work with pipe when curried', () => {
45
45
  const pickIdAndName = Obj.pick(['id', 'name']);
46
46
  const user = { id: 1, name: 'Alice', email: 'alice@example.com', age: 30 };
47
47
 
@@ -49,13 +49,13 @@ describe('pick', () => {
49
49
  expect(result).toStrictEqual({ id: 1, name: 'Alice' });
50
50
  });
51
51
 
52
- test('should handle empty keys in curried form', () => {
52
+ test('pick should handle empty keys in curried form', () => {
53
53
  const pickNone = Obj.pick([]);
54
54
  const result = pickNone({ a: 1, b: 2 });
55
55
  expect(result).toStrictEqual({});
56
56
  });
57
57
 
58
- test('should work for records that only partially contain the key in curried form', () => {
58
+ test('pick should work for records that only partially contain the key in curried form', () => {
59
59
  const pickVisible = Obj.pick(['name', 'age']);
60
60
  const user = {
61
61
  id: 1,
@@ -71,17 +71,17 @@ describe('pick', () => {
71
71
  });
72
72
 
73
73
  describe('omit', () => {
74
- test('truthy case 1', () => {
74
+ test('should omit specified keys', () => {
75
75
  expect(Obj.omit({ a: 1, b: 2, c: 3 }, ['c'])).toStrictEqual({ a: 1, b: 2 });
76
76
  });
77
77
 
78
- test('should support curried form', () => {
78
+ test('omit should support curried form', () => {
79
79
  const omitC = Obj.omit(['c']);
80
80
  const result = omitC({ a: 1, b: 2, c: 3, d: 4 });
81
81
  expect(result).toStrictEqual({ a: 1, b: 2, d: 4 });
82
82
  });
83
83
 
84
- test('should work with pipe when curried', () => {
84
+ test('omit should work with pipe when curried', () => {
85
85
  const omitSensitive = Obj.omit(['password', 'email']);
86
86
  const user = {
87
87
  id: 1,
@@ -94,7 +94,7 @@ describe('omit', () => {
94
94
  expect(result).toStrictEqual({ id: 1, name: 'Alice' });
95
95
  });
96
96
 
97
- test('should handle empty keys in curried form', () => {
97
+ test('omit should handle empty keys in curried form', () => {
98
98
  const omitNone = Obj.omit([]);
99
99
  const original = { a: 1, b: 2, c: 3 };
100
100
  const result = omitNone(original);
@@ -107,7 +107,7 @@ describe('omit', () => {
107
107
  expect(result).toStrictEqual({ a: 1, c: 3, e: 5 });
108
108
  });
109
109
 
110
- test('should work for records that only partially contain the key in curried form', () => {
110
+ test('omit should work for records that only partially contain the key in curried form', () => {
111
111
  const omitSensitive = Obj.omit(['password', 'email']);
112
112
  const user = {
113
113
  id: 1,
@@ -25,16 +25,16 @@ describe('castReadonly', () => {
25
25
  expect(Object.is(readonly, original)).toBe(true);
26
26
  });
27
27
 
28
- test('should work with primitives', () => {
28
+ test('castReadonly should work with primitives', () => {
29
29
  expect(castReadonly(42)).toBe(42);
30
30
  expect(castReadonly('hello')).toBe('hello');
31
31
  expect(castReadonly(true)).toBe(true);
32
32
  });
33
33
 
34
- test('should work with null and undefined', () => {
35
- expect(castReadonly(null)).toBe(null);
34
+ test('castReadonly should work with null and undefined', () => {
35
+ expect(castReadonly(null)).toBeNull();
36
36
  // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
37
- expect(castReadonly(undefined)).toBe(undefined);
37
+ expect(castReadonly(undefined)).toBeUndefined();
38
38
  });
39
39
  });
40
40
 
@@ -75,15 +75,15 @@ describe('castDeepReadonly', () => {
75
75
  expect(readonly[1]?.meta.active).toBe(false);
76
76
  });
77
77
 
78
- test('should work with primitives', () => {
78
+ test('castDeepReadonly should work with primitives', () => {
79
79
  expect(castDeepReadonly(42)).toBe(42);
80
80
  expect(castDeepReadonly('hello')).toBe('hello');
81
81
  expect(castDeepReadonly(true)).toBe(true);
82
82
  });
83
83
 
84
- test('should work with null and undefined', () => {
85
- expect(castDeepReadonly(null)).toBe(null);
84
+ test('castDeepReadonly should work with null and undefined', () => {
85
+ expect(castDeepReadonly(null)).toBeNull();
86
86
  // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
87
- expect(castDeepReadonly(undefined)).toBe(undefined);
87
+ expect(castDeepReadonly(undefined)).toBeUndefined();
88
88
  });
89
89
  });
@@ -101,7 +101,7 @@
101
101
  * const memoizedFindPaths = memoizeFunction(
102
102
  * findPaths,
103
103
  * (start, end, visited = new Set()) =>
104
- * `${start}->${end}:[${[...visited].sort().join(',')}]`
104
+ * `${start}->${end}:[${[...visited].toSorted().join(',')}]`
105
105
  * );
106
106
  * ```
107
107
  *
@@ -37,12 +37,12 @@ describe('memoizeFunction', () => {
37
37
  const memoized = memoizeFunction(mockFn, (x) => x);
38
38
 
39
39
  // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
40
- expect(memoized(5)).toBe(undefined);
40
+ expect(memoized(5)).toBeUndefined();
41
41
  expect(mockFn).toHaveBeenCalledTimes(1);
42
42
 
43
43
  // Should use cache even for undefined
44
44
  // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
45
- expect(memoized(5)).toBe(undefined);
45
+ expect(memoized(5)).toBeUndefined();
46
46
  expect(mockFn).toHaveBeenCalledTimes(1);
47
47
  });
48
48
 
@@ -1,4 +1,3 @@
1
- import { Result } from '../functional/index.mjs';
2
1
  import { isNonNullish } from '../guard/index.mjs';
3
2
 
4
3
  /**
@@ -20,22 +19,22 @@ import { isNonNullish } from '../guard/index.mjs';
20
19
  * @param value - The unknown value to convert to string
21
20
  * @param options - Optional configuration for the conversion
22
21
  * @param options.prettyPrintObject - If true, objects are formatted with 2-space indentation
23
- * @returns A Result containing either the string representation or an Error for failures
22
+ * @returns The string representation of the value. For circular references or non-serializable objects, returns an error message string
24
23
  *
25
24
  * @example Basic type conversions
26
25
  * ```typescript
27
26
  * // Primitive types
28
- * unknownToString('hello'); // Ok('hello')
29
- * unknownToString(123); // Ok('123')
30
- * unknownToString(true); // Ok('true')
31
- * unknownToString(null); // Ok('null')
32
- * unknownToString(undefined); // Ok('undefined')
33
- * unknownToString(Symbol('test')); // Ok('Symbol(test)')
34
- * unknownToString(123n); // Ok('123')
27
+ * unknownToString('hello'); // 'hello'
28
+ * unknownToString(123); // '123'
29
+ * unknownToString(true); // 'true'
30
+ * unknownToString(null); // 'null'
31
+ * unknownToString(undefined); // 'undefined'
32
+ * unknownToString(Symbol('test')); // 'Symbol(test)'
33
+ * unknownToString(123n); // '123'
35
34
  *
36
35
  * // Function conversion
37
36
  * const fn = () => 'test';
38
- * unknownToString(fn); // Ok('() => 'test'')
37
+ * unknownToString(fn); // "() => 'test'"
39
38
  * ```
40
39
  *
41
40
  * @example Object stringification
@@ -43,24 +42,20 @@ import { isNonNullish } from '../guard/index.mjs';
43
42
  * // Simple object
44
43
  * const obj = { a: 1, b: 'hello', c: [1, 2, 3] };
45
44
  * const result = unknownToString(obj);
46
- * if (Result.isOk(result)) {
47
- * console.log(result.value); // '{"a":1,"b":"hello","c":[1,2,3]}'
48
- * }
45
+ * console.log(result); // '{"a":1,"b":"hello","c":[1,2,3]}'
49
46
  *
50
47
  * // Pretty printing
51
48
  * const prettyResult = unknownToString(obj, { prettyPrintObject: true });
52
- * if (Result.isOk(prettyResult)) {
53
- * console.log(prettyResult.value);
54
- * // {
55
- * // "a": 1,
56
- * // "b": "hello",
57
- * // "c": [
58
- * // 1,
59
- * // 2,
60
- * // 3
61
- * // ]
62
- * // }
63
- * }
49
+ * console.log(prettyResult);
50
+ * // {
51
+ * // "a": 1,
52
+ * // "b": "hello",
53
+ * // "c": [
54
+ * // 1,
55
+ * // 2,
56
+ * // 3
57
+ * // ]
58
+ * // }
64
59
  * ```
65
60
  *
66
61
  * @example Error handling for circular references
@@ -70,19 +65,7 @@ import { isNonNullish } from '../guard/index.mjs';
70
65
  * circular.self = circular;
71
66
  *
72
67
  * const result = unknownToString(circular);
73
- * if (Result.isErr(result)) {
74
- * console.log(result.value.message);
75
- * // "Converting circular structure to JSON"
76
- * }
77
- *
78
- * // Handle with custom serialization
79
- * const safeStringify = (value: unknown): string => {
80
- * const result = unknownToString(value);
81
- * return Result.isOk(result)
82
- * ? result.value
83
- * : `[Error: ${result.value.message}]`;
84
- * };
85
- * ```
68
+ * console.log(result); // "Converting circular structure to JSON"
86
69
  *
87
70
  * @example Logging and debugging utilities
88
71
  * ```typescript
@@ -92,13 +75,9 @@ import { isNonNullish } from '../guard/index.mjs';
92
75
  * const timestamp = new Date().toISOString();
93
76
  * const dataStr = data !== undefined
94
77
  * ? unknownToString(data, { prettyPrintObject: true })
95
- * : Result.ok('');
78
+ * : '';
96
79
  *
97
- * if (Result.isOk(dataStr)) {
98
- * console.log(`[${timestamp}] ${message}`, dataStr.value);
99
- * } else {
100
- * console.log(`[${timestamp}] ${message} [Unstringifiable data]`);
101
- * }
80
+ * console.log(`[${timestamp}] ${message}`, dataStr);
102
81
  * }
103
82
  * }
104
83
  *
@@ -110,19 +89,11 @@ import { isNonNullish } from '../guard/index.mjs';
110
89
  * ```typescript
111
90
  * // Safe error response formatting
112
91
  * function formatErrorResponse(error: unknown): string {
113
- * const result = unknownToString(error, { prettyPrintObject: true });
92
+ * const errorStr = unknownToString(error, { prettyPrintObject: true });
114
93
  *
115
- * if (Result.isOk(result)) {
116
- * return JSON.stringify({
117
- * success: false,
118
- * error: result.value
119
- * });
120
- * }
121
- *
122
- * // Fallback for unstringifiable errors
123
94
  * return JSON.stringify({
124
95
  * success: false,
125
- * error: 'An unknown error occurred'
96
+ * error: errorStr
126
97
  * });
127
98
  * }
128
99
  *
@@ -138,78 +109,72 @@ import { isNonNullish } from '../guard/index.mjs';
138
109
  * ```typescript
139
110
  * // Date objects
140
111
  * unknownToString(new Date('2023-01-01'));
141
- * // Ok('"2023-01-01T00:00:00.000Z"') - JSON stringified
112
+ * // '"2023-01-01T00:00:00.000Z"' - JSON stringified
142
113
  *
143
114
  * // Regular expressions
144
115
  * unknownToString(/test/gi);
145
- * // Ok('{}') - RegExp has no enumerable properties
116
+ * // '{}' - RegExp has no enumerable properties
146
117
  *
147
118
  * // Arrays
148
119
  * unknownToString([1, 'two', { three: 3 }]);
149
- * // Ok('[1,"two",{"three":3}]')
120
+ * // '[1,"two",{"three":3}]'
150
121
  *
151
122
  * // Map and Set (converted to empty objects by JSON.stringify)
152
- * unknownToString(new Map([['a', 1]])); // Ok('{}')
153
- * unknownToString(new Set([1, 2, 3])); // Ok('{}')
123
+ * unknownToString(new Map([['a', 1]])); // '{}'
124
+ * unknownToString(new Set([1, 2, 3])); // '{}'
154
125
  * ```
155
126
  *
156
- * @example Integration with Result type
127
+ * @example Using with validation
157
128
  * ```typescript
158
- * import { Result, pipe } from '../functional';
159
- *
160
- * // Chain with other Result operations
161
- * function processUserInput(input: unknown): Result<string, Error> {
162
- * return pipe(input)
163
- * .map(val => unknownToString(val))
164
- * .map(Result.flatten) // Flatten Result<Result<string, Error>, never>
165
- * .map(str => Result.map(str, s => s.trim()))
166
- * .map(Result.flatten)
167
- * .map(str => Result.flatMap(str, s =>
168
- * s.length > 0
169
- * ? Result.ok(s)
170
- * : Result.err(new Error('Empty string'))
171
- * ))
172
- * .value;
129
+ * // Simple validation helper
130
+ * function validateAndStringify(input: unknown): string {
131
+ * const str = unknownToString(input);
132
+ * const trimmed = str.trim();
133
+ *
134
+ * if (trimmed.length === 0) {
135
+ * throw new Error('Empty string');
136
+ * }
137
+ *
138
+ * return trimmed;
173
139
  * }
174
140
  * ```
175
141
  *
176
- * @see Result - For error handling pattern used by this function
142
+ * **Error Handling:**
143
+ * Circular references and non-serializable objects return descriptive error messages instead of throwing
177
144
  * @see JSON.stringify - Underlying serialization for objects
178
145
  */
179
146
  export const unknownToString = (
180
147
  value: unknown,
181
148
  options?: Partial<Readonly<{ prettyPrintObject: boolean }>>,
182
- ): Result<string, Error> => {
149
+ ): string => {
183
150
  switch (typeof value) {
184
151
  case 'string':
185
- return Result.ok(value);
152
+ return value;
186
153
 
187
154
  case 'number':
188
155
  case 'bigint':
189
156
  case 'boolean':
190
157
  case 'symbol':
191
158
  case 'function':
192
- return Result.ok(value.toString());
159
+ return value.toString();
193
160
 
194
161
  case 'object':
195
162
  if (!isNonNullish(value)) {
196
- return Result.ok('null');
163
+ return 'null';
197
164
  }
198
165
  try {
199
166
  const stringified =
200
167
  options?.prettyPrintObject === true
201
168
  ? JSON.stringify(value, undefined, 2)
202
169
  : JSON.stringify(value);
203
- return Result.ok(stringified);
170
+ return stringified;
204
171
  } catch (error) {
205
- return Result.err(
206
- error instanceof Error
207
- ? error
208
- : new Error('Failed to stringify object'),
209
- );
172
+ return error instanceof Error
173
+ ? error.message
174
+ : '[Circular or Non-serializable]';
210
175
  }
211
176
 
212
177
  case 'undefined':
213
- return Result.ok('undefined');
178
+ return 'undefined';
214
179
  }
215
180
  };
@@ -1,76 +1,51 @@
1
- import { Result } from '../functional/index.mjs';
2
1
  import { unknownToString } from './unknown-to-string.mjs';
3
2
 
4
3
  describe('unknownToString', () => {
5
4
  test('string', () => {
6
5
  const result = unknownToString('aaaaa');
7
- expect(Result.isOk(result)).toBe(true);
8
- if (Result.isOk(result)) {
9
- expect(result.value).toBe('aaaaa');
10
- }
6
+ expect(result).toBe('aaaaa');
11
7
  expect(JSON.stringify('aaaaa')).toBe('"aaaaa"');
12
8
  });
13
9
 
14
10
  test('number', () => {
15
11
  const result = unknownToString(1);
16
- expect(Result.isOk(result)).toBe(true);
17
- if (Result.isOk(result)) {
18
- expect(result.value).toBe('1');
19
- }
12
+ expect(result).toBe('1');
20
13
  expect(JSON.stringify(1)).toBe('1');
21
14
  });
22
15
 
23
16
  test('boolean', () => {
24
17
  const result = unknownToString(true);
25
- expect(Result.isOk(result)).toBe(true);
26
- if (Result.isOk(result)) {
27
- expect(result.value).toBe('true');
28
- }
18
+ expect(result).toBe('true');
29
19
  expect(JSON.stringify(true)).toBe('true');
30
20
  });
31
21
 
32
22
  test('symbol', () => {
33
23
  const result = unknownToString(Symbol('sym'));
34
- expect(Result.isOk(result)).toBe(true);
35
- if (Result.isOk(result)) {
36
- expect(result.value).toBe('Symbol(sym)');
37
- }
24
+ expect(result).toBe('Symbol(sym)');
38
25
  expect(JSON.stringify(Symbol('sym'))).toBeUndefined();
39
26
  });
40
27
 
41
28
  test('function', () => {
42
29
  const result = unknownToString(() => 0);
43
- expect(Result.isOk(result)).toBe(true);
44
- if (Result.isOk(result)) {
45
- expect(result.value).toBe('() => 0');
46
- }
30
+ expect(result).toBe('() => 0');
47
31
  expect(JSON.stringify(() => 0)).toBeUndefined();
48
32
  });
49
33
 
50
34
  test('undefined', () => {
51
35
  const result = unknownToString(undefined);
52
- expect(Result.isOk(result)).toBe(true);
53
- if (Result.isOk(result)) {
54
- expect(result.value).toBe('undefined');
55
- }
36
+ expect(result).toBe('undefined');
56
37
  expect(JSON.stringify(undefined)).toBeUndefined();
57
38
  });
58
39
 
59
40
  test('null', () => {
60
41
  const result = unknownToString(null);
61
- expect(Result.isOk(result)).toBe(true);
62
- if (Result.isOk(result)) {
63
- expect(result.value).toBe('null');
64
- }
42
+ expect(result).toBe('null');
65
43
  expect(JSON.stringify(null)).toBe('null');
66
44
  });
67
45
 
68
46
  test('object', () => {
69
47
  const result = unknownToString({ a: { b: 1 } });
70
- expect(Result.isOk(result)).toBe(true);
71
- if (Result.isOk(result)) {
72
- expect(result.value).toBe('{"a":{"b":1}}');
73
- }
48
+ expect(result).toBe('{"a":{"b":1}}');
74
49
  expect(JSON.stringify({ a: { b: 1 } })).toBe('{"a":{"b":1}}');
75
50
  });
76
51
 
@@ -79,36 +54,29 @@ describe('unknownToString', () => {
79
54
  { a: { b: 1 } },
80
55
  { prettyPrintObject: true },
81
56
  );
82
- expect(Result.isOk(result)).toBe(true);
83
- if (Result.isOk(result)) {
84
- expect(result.value).toBe(
85
- [
86
- //
87
- `{`,
88
- ` "a": {`,
89
- ` "b": 1`,
90
- ` }`,
91
- `}`,
92
- ].join('\n'),
93
- );
94
- }
57
+ expect(result).toBe(
58
+ [
59
+ //
60
+ `{`,
61
+ ` "a": {`,
62
+ ` "b": 1`,
63
+ ` }`,
64
+ `}`,
65
+ ].join('\n'),
66
+ );
95
67
  });
96
68
 
97
- test('circular reference returns error', () => {
98
- const circular: { a: number; self?: unknown } = { a: 1 };
99
- circular.self = circular;
100
- const result = unknownToString(circular);
101
- expect(Result.isErr(result)).toBe(true);
102
- if (Result.isErr(result)) {
103
- expect(result.value.message).toContain('circular');
104
- }
69
+ test('circular reference returns error message', () => {
70
+ const mut_circular: { a: number; self?: unknown } = { a: 1 };
71
+ mut_circular.self = mut_circular;
72
+ const result = unknownToString(mut_circular);
73
+ // Should return an error message string instead of throwing
74
+ expect(typeof result).toBe('string');
75
+ expect(result).toMatch(/circular|serialize/iu);
105
76
  });
106
77
 
107
78
  test('BigInt value', () => {
108
79
  const result = unknownToString(BigInt(123));
109
- expect(Result.isOk(result)).toBe(true);
110
- if (Result.isOk(result)) {
111
- expect(result.value).toBe('123');
112
- }
80
+ expect(result).toBe('123');
113
81
  });
114
82
  });