ts-fortress 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +135 -0
  2. package/dist/array/array-of-length.d.mts.map +1 -1
  3. package/dist/array/array-of-length.mjs +8 -6
  4. package/dist/array/array-of-length.mjs.map +1 -1
  5. package/dist/array/array.d.mts.map +1 -1
  6. package/dist/array/array.mjs +8 -6
  7. package/dist/array/array.mjs.map +1 -1
  8. package/dist/array/non-empty-array.d.mts.map +1 -1
  9. package/dist/array/non-empty-array.mjs +8 -6
  10. package/dist/array/non-empty-array.mjs.map +1 -1
  11. package/dist/array/tuple.d.mts.map +1 -1
  12. package/dist/array/tuple.mjs +8 -6
  13. package/dist/array/tuple.mjs.map +1 -1
  14. package/dist/compose/intersection.d.mts.map +1 -1
  15. package/dist/compose/intersection.mjs +10 -10
  16. package/dist/compose/intersection.mjs.map +1 -1
  17. package/dist/compose/merge-records.d.mts.map +1 -1
  18. package/dist/compose/merge-records.mjs +10 -10
  19. package/dist/compose/merge-records.mjs.map +1 -1
  20. package/dist/compose/union.d.mts.map +1 -1
  21. package/dist/compose/union.mjs.map +1 -1
  22. package/dist/enum/enum.d.mts.map +1 -1
  23. package/dist/enum/enum.mjs.map +1 -1
  24. package/dist/enum/uint-range.d.mts.map +1 -1
  25. package/dist/enum/uint-range.mjs.map +1 -1
  26. package/dist/index.d.mts +0 -1
  27. package/dist/index.d.mts.map +1 -1
  28. package/dist/index.mjs +1 -1
  29. package/dist/record/key-value-record.d.mts.map +1 -1
  30. package/dist/record/key-value-record.mjs +21 -24
  31. package/dist/record/key-value-record.mjs.map +1 -1
  32. package/dist/record/omit.d.mts.map +1 -1
  33. package/dist/record/omit.mjs +3 -2
  34. package/dist/record/omit.mjs.map +1 -1
  35. package/dist/record/partial.d.mts.map +1 -1
  36. package/dist/record/partial.mjs +2 -2
  37. package/dist/record/partial.mjs.map +1 -1
  38. package/dist/record/pick.d.mts.map +1 -1
  39. package/dist/record/pick.mjs +2 -2
  40. package/dist/record/pick.mjs.map +1 -1
  41. package/dist/record/record.d.mts +6 -2
  42. package/dist/record/record.d.mts.map +1 -1
  43. package/dist/record/record.mjs +23 -21
  44. package/dist/record/record.mjs.map +1 -1
  45. package/dist/type.d.mts +1 -1
  46. package/dist/type.d.mts.map +1 -1
  47. package/dist/utils/create-assert-fn.mjs +1 -1
  48. package/dist/utils/create-cast-fn.mjs +1 -1
  49. package/dist/utils/create-primitive-type.mjs +1 -1
  50. package/dist/utils/index.d.mts +1 -0
  51. package/dist/utils/index.d.mts.map +1 -1
  52. package/dist/utils/index.mjs +1 -0
  53. package/dist/utils/index.mjs.map +1 -1
  54. package/dist/utils/validation-error.d.mts.map +1 -0
  55. package/dist/utils/validation-error.mjs.map +1 -0
  56. package/package.json +4 -2
  57. package/src/array/array-of-length.mts +12 -7
  58. package/src/array/array-of-length.test.mts +10 -1
  59. package/src/array/array.mts +12 -7
  60. package/src/array/array.test.mts +10 -1
  61. package/src/array/non-empty-array.mts +11 -7
  62. package/src/array/non-empty-array.test.mts +10 -1
  63. package/src/array/tuple.mts +11 -9
  64. package/src/array/tuple.test.mts +14 -1
  65. package/src/branded/brand.mts +2 -2
  66. package/src/branded/number/finite-number.test.mts +10 -1
  67. package/src/branded/number/int.test.mts +10 -1
  68. package/src/branded/number/int16.test.mts +10 -1
  69. package/src/branded/number/int32.test.mts +10 -1
  70. package/src/branded/number/non-negative-finite-number.test.mts +10 -1
  71. package/src/branded/number/non-zero-finite-number.test.mts +10 -1
  72. package/src/branded/number/non-zero-int.test.mts +10 -1
  73. package/src/branded/number/non-zero-safe-int.test.mts +10 -1
  74. package/src/branded/number/positive-finite-number.test.mts +10 -1
  75. package/src/branded/number/positive-int.test.mts +10 -1
  76. package/src/branded/number/positive-safe-int.test.mts +10 -1
  77. package/src/branded/number/safe-int.test.mts +10 -1
  78. package/src/branded/number/safe-uint.test.mts +10 -1
  79. package/src/branded/number/uint.test.mts +10 -1
  80. package/src/branded/number/uint16.test.mts +10 -1
  81. package/src/branded/number/uint32.test.mts +10 -1
  82. package/src/branded/simple-branded-number.test.mts +19 -1
  83. package/src/branded/simple-branded-string.test.mts +19 -1
  84. package/src/compose/intersection.mts +23 -19
  85. package/src/compose/intersection.test.mts +28 -1
  86. package/src/compose/merge-records.mts +22 -19
  87. package/src/compose/merge-records.test.mts +10 -1
  88. package/src/compose/union.mts +6 -2
  89. package/src/compose/union.test.mts +10 -1
  90. package/src/enum/enum.mts +6 -2
  91. package/src/enum/enum.test.mts +10 -1
  92. package/src/enum/uint-range.mts +6 -2
  93. package/src/enum/uint-range.test.mts +10 -1
  94. package/src/index.mts +0 -1
  95. package/src/primitives/bigint.test.mts +19 -1
  96. package/src/primitives/boolean.test.mts +28 -1
  97. package/src/primitives/null.test.mts +9 -0
  98. package/src/primitives/number.test.mts +18 -0
  99. package/src/primitives/string.test.mts +18 -0
  100. package/src/primitives/symbol.test.mts +10 -1
  101. package/src/primitives/undefined.test.mts +9 -0
  102. package/src/record/key-value-record.mts +34 -36
  103. package/src/record/key-value-record.test.mts +14 -1
  104. package/src/record/keyof.test.mts +10 -1
  105. package/src/record/omit.mts +8 -5
  106. package/src/record/omit.test.mts +46 -1
  107. package/src/record/partial.mts +7 -5
  108. package/src/record/partial.test.mts +71 -1
  109. package/src/record/pick.mts +7 -5
  110. package/src/record/pick.test.mts +46 -1
  111. package/src/record/record-allow-excess-properties.test.mts +28 -1
  112. package/src/record/record-strict-composition-simple.test.mts +38 -0
  113. package/src/record/record-strict-composition.test.mts +71 -0
  114. package/src/record/record.mts +50 -36
  115. package/src/record/record.test.mts +26 -1
  116. package/src/record/strict-record.test.mts +10 -1
  117. package/src/type.mts +1 -1
  118. package/src/utils/create-assert-fn.mts +1 -1
  119. package/src/utils/create-cast-fn.mts +1 -1
  120. package/src/utils/create-primitive-type.mts +1 -1
  121. package/src/utils/index.mts +1 -0
  122. package/dist/validation-error.d.mts.map +0 -1
  123. package/dist/validation-error.mjs.map +0 -1
  124. package/src/combination.test.mts +0 -544
  125. /package/dist/{validation-error.d.mts → utils/validation-error.d.mts} +0 -0
  126. /package/dist/{validation-error.mjs → utils/validation-error.mjs} +0 -0
  127. /package/src/{validation-error.mts → utils/validation-error.mts} +0 -0
  128. /package/src/{validation-error.test.mts → utils/validation-error.test.mts} +0 -0
@@ -1,544 +0,0 @@
1
- import { asInt, expectType, Result } from 'ts-data-forge';
2
- import { array } from './array/index.mjs';
3
- import { int } from './branded/index.mjs';
4
- import { union } from './compose/index.mjs';
5
- import { uintRange } from './enum/index.mjs';
6
- import { nullType, number, undefinedType } from './primitives/index.mjs';
7
- import { keyof, optional, partial, pick, record } from './record/index.mjs';
8
- import { type TypeOf } from './type.mjs';
9
- import { unknown } from './unknown.mjs';
10
- import { validationErrorsToMessages } from './validation-error.mjs';
11
-
12
- describe('nested record', () => {
13
- const nestedRecord = record({
14
- xs: array(int(asInt(2))),
15
- rec: pick(
16
- record({
17
- a: uintRange({ start: 0, end: 11, defaultValue: 0 }),
18
- b: uintRange({ start: 0, end: 11, defaultValue: 0 }),
19
- c: optional(uintRange({ start: 3, end: 6, defaultValue: 3 })),
20
- d: unknown(),
21
- }),
22
- ['a', 'b', 'c'],
23
- ),
24
- meta: number(100),
25
- u: unknown(),
26
- });
27
-
28
- type NestedRecord = TypeOf<typeof nestedRecord>;
29
-
30
- expectType<
31
- NestedRecord,
32
- Readonly<{
33
- xs: readonly Int[];
34
- rec: Readonly<{
35
- a: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
36
- b: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
37
- c?: 3 | 4 | 5;
38
- }>;
39
- meta: number;
40
- u: unknown;
41
- }>
42
- >('=');
43
-
44
- expectType<typeof nestedRecord.defaultValue, NestedRecord>('=');
45
-
46
- describe('is', () => {
47
- test('truthy case', () => {
48
- const x: UnknownRecord = {
49
- xs: [1, 2, 3],
50
- rec: {
51
- a: 1,
52
- b: 2,
53
- c: 3,
54
- },
55
- meta: 3,
56
- u: undefined,
57
- };
58
-
59
- if (nestedRecord.is(x)) {
60
- expectType<typeof x, NestedRecord>('=');
61
- } else {
62
- expectType<typeof x, UnknownRecord>('=');
63
- }
64
-
65
- expect(nestedRecord.is(x)).toBe(true);
66
- });
67
-
68
- test('falsy case', () => {
69
- const x: UnknownRecord = {
70
- xs: [-1, 2.2, 3.3],
71
- rec: {
72
- a: 123,
73
- b: 234,
74
- c: 3,
75
- },
76
- meta: 345,
77
- u: undefined,
78
- };
79
-
80
- if (nestedRecord.is(x)) {
81
- expectType<typeof x, NestedRecord>('=');
82
- } else {
83
- expectType<typeof x, UnknownRecord>('=');
84
- }
85
-
86
- expect(nestedRecord.is(x)).toBe(false);
87
- });
88
- });
89
-
90
- describe('validate', () => {
91
- test('falsy case', () => {
92
- const x: UnknownRecord = {
93
- xs: [-1, 2.2, 3.3],
94
- rec: {
95
- a: 123,
96
- b: 234,
97
- c: 3,
98
- },
99
- meta: 345,
100
- u: undefined,
101
- };
102
-
103
- const result = nestedRecord.validate(x);
104
- expect(Result.isErr(result)).toBe(true);
105
-
106
- if (Result.isErr(result)) {
107
- expect(result.value).toStrictEqual([
108
- {
109
- path: ['xs', '1'],
110
- actualValue: 2.2,
111
- expectedType: 'Finite & Int & not(NaNValue)',
112
- typeName: 'Finite & Int & not(NaNValue)',
113
- message:
114
- 'The value must satisfy the constraint corresponding to the brand keys: <Finite & Int & not(NaNValue)>',
115
- },
116
- {
117
- path: ['xs', '2'],
118
- actualValue: 3.3,
119
- expectedType: 'Finite & Int & not(NaNValue)',
120
- typeName: 'Finite & Int & not(NaNValue)',
121
- message:
122
- 'The value must satisfy the constraint corresponding to the brand keys: <Finite & Int & not(NaNValue)>',
123
- },
124
- {
125
- path: ['rec', 'a'],
126
- actualValue: 123,
127
- expectedType: 'uintRange(0, 11)',
128
- typeName: 'uintRange(0, 11)',
129
- message: 'The value is expected to be an integer between 0 and 10',
130
- },
131
- {
132
- path: ['rec', 'b'],
133
- actualValue: 234,
134
- expectedType: 'uintRange(0, 11)',
135
- typeName: 'uintRange(0, 11)',
136
- message: 'The value is expected to be an integer between 0 and 10',
137
- },
138
- ]);
139
- expect(validationErrorsToMessages(result.value)).toStrictEqual([
140
- 'The value must satisfy the constraint corresponding to the brand keys: <Finite & Int & not(NaNValue)> at xs.1',
141
- 'The value must satisfy the constraint corresponding to the brand keys: <Finite & Int & not(NaNValue)> at xs.2',
142
- 'The value is expected to be an integer between 0 and 10 at rec.a',
143
- 'The value is expected to be an integer between 0 and 10 at rec.b',
144
- ]);
145
- }
146
- });
147
- });
148
-
149
- describe('fill', () => {
150
- test('from an empty record', () => {
151
- const x: UnknownRecord = {};
152
-
153
- expect(nestedRecord.fill(x)).toStrictEqual({
154
- xs: [],
155
- rec: {
156
- a: 0,
157
- b: 0,
158
- c: 3,
159
- },
160
- meta: 100,
161
- u: undefined,
162
- });
163
- });
164
-
165
- test('from a filled record', () => {
166
- const x: UnknownRecord = {
167
- xs: [-1, 2.2, 3.3],
168
- rec: {
169
- a: 123,
170
- b: 234,
171
- c: 3,
172
- },
173
- meta: 345,
174
- u: undefined,
175
- };
176
-
177
- expect(nestedRecord.fill(x)).toStrictEqual({
178
- xs: [-1, 2, 2],
179
- rec: {
180
- a: 0,
181
- b: 0,
182
- c: 3,
183
- },
184
- meta: 345,
185
- u: undefined,
186
- });
187
- });
188
-
189
- test('from a partial record', () => {
190
- const x: UnknownRecord = {
191
- xs: [11, 22],
192
- rec: {
193
- a: 3,
194
- },
195
- };
196
-
197
- expect(nestedRecord.fill(x)).toStrictEqual({
198
- xs: [11, 22],
199
- rec: {
200
- a: 3,
201
- b: 0,
202
- c: 3,
203
- },
204
- meta: 100,
205
- u: undefined,
206
- });
207
- });
208
-
209
- test('from a partial record with excess property', () => {
210
- const x: UnknownRecord = {
211
- xs: [11, 22],
212
- rec: {
213
- a: 3,
214
- d: 9988,
215
- },
216
- u: undefined,
217
- aaaaa: [9999],
218
- };
219
-
220
- expect(nestedRecord.fill(x)).toStrictEqual({
221
- xs: [11, 22],
222
- rec: {
223
- a: 3,
224
- b: 0,
225
- c: 3,
226
- },
227
- meta: 100,
228
- u: undefined,
229
- });
230
- });
231
- });
232
- });
233
-
234
- describe('ymd', () => {
235
- const ymd = record({
236
- year: number(1900),
237
- month: number(1),
238
- date: number(1),
239
- });
240
-
241
- test('is', () => {
242
- const x = {
243
- year: 2000,
244
- };
245
-
246
- expect(ymd.is(x)).toBe(false);
247
- });
248
-
249
- test('fill', () => {
250
- const x = {
251
- year: 2000,
252
- };
253
-
254
- expect(ymd.fill(x)).toStrictEqual({
255
- year: 2000,
256
- month: 1,
257
- date: 1,
258
- });
259
- });
260
-
261
- test('assertion function', () => {
262
- type YMD = TypeOf<typeof ymd>;
263
-
264
- const assertIsYmd: (a: unknown) => asserts a is YMD = ymd.assertIs;
265
-
266
- const x = {
267
- year: 2000,
268
- };
269
-
270
- const f = (): void => {
271
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
272
- // @ts-expect-error
273
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
274
- x.month;
275
-
276
- assertIsYmd(x); // throws an error
277
-
278
- expectType<typeof x.month, number>('='); // no type error
279
- };
280
-
281
- expect(f).toThrow(
282
- '\nMissing required key "month" at month,\nMissing required key "date" at date',
283
- );
284
- });
285
-
286
- test('validation function', () => {
287
- const x = {
288
- year: 2000,
289
- };
290
-
291
- const result = ymd.validate(x);
292
-
293
- expect(Result.isErr(result)).toBe(true);
294
-
295
- if (Result.isErr(result)) {
296
- expect(result.value).toStrictEqual([
297
- {
298
- path: ['month'],
299
- actualValue: x,
300
- expectedType: '{ year: number, month: number, date: number }',
301
- typeName: '{ year: number, month: number, date: number }',
302
- message: 'Missing required key "month"',
303
- },
304
- {
305
- path: ['date'],
306
- actualValue: x,
307
- expectedType: '{ year: number, month: number, date: number }',
308
- typeName: '{ year: number, month: number, date: number }',
309
- message: 'Missing required key "date"',
310
- },
311
- ]);
312
- expect(validationErrorsToMessages(result.value)).toStrictEqual([
313
- 'Missing required key "month" at month',
314
- 'Missing required key "date" at date',
315
- ]);
316
- }
317
- });
318
- });
319
-
320
- describe('ymd2', () => {
321
- const ymd2 = record({
322
- year: int(asInt(1900)),
323
- month: uintRange({
324
- defaultValue: 1,
325
- start: 1,
326
- end: 13,
327
- }),
328
- date: uintRange({
329
- defaultValue: 1,
330
- start: 1,
331
- end: 32,
332
- }),
333
- });
334
-
335
- type YMD2 = TypeOf<typeof ymd2>;
336
-
337
- expectType<YMD2['month'], 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12>(
338
- '=',
339
- );
340
-
341
- test('is', () => {
342
- const x = {
343
- year: 2000,
344
- };
345
-
346
- expect(ymd2.is(x)).toBe(false);
347
- });
348
- });
349
-
350
- // Tests demonstrating ts-fortress correct behavior for io-ts bugs mentioned in README
351
- describe('io-ts bug examples - correct behavior in ts-fortress', () => {
352
- describe('keyof type consistency (io-ts issue #697)', () => {
353
- test('keyof with numeric keys produces correct types and runtime behavior', () => {
354
- // ts-fortress: Runtime and types always match
355
- const T = keyof(
356
- record({
357
- 0: undefinedType,
358
- 1: undefinedType,
359
- 2: undefinedType,
360
- 3: undefinedType,
361
- 4: undefinedType,
362
- }),
363
- );
364
-
365
- type T = TypeOf<typeof T>;
366
- // TypeScript correctly infers: "0" | "1" | "2" | "3" | "4" (string literals)
367
- expectType<T, '0' | '1' | '2' | '3' | '4'>('=');
368
-
369
- // Runtime behavior matches TypeScript types exactly
370
- expect(Result.isErr(T.validate(0))).toBe(true); // number 0 is rejected
371
- expect(Result.isOk(T.validate('0'))).toBe(true); // string "0" is accepted
372
-
373
- expect(Result.isOk(T.validate('1'))).toBe(true);
374
- expect(Result.isOk(T.validate('2'))).toBe(true);
375
- expect(Result.isOk(T.validate('3'))).toBe(true);
376
- expect(Result.isOk(T.validate('4'))).toBe(true);
377
-
378
- expect(Result.isErr(T.validate('5'))).toBe(true); // invalid key
379
- expect(Result.isErr(T.validate(1))).toBe(true); // number literal rejected
380
- expect(Result.isErr(T.validate('invalid'))).toBe(true); // invalid string
381
- });
382
- });
383
-
384
- describe('union validation consistency (io-ts issue #677)', () => {
385
- test('union validation produces predictable results without unexpected fields', () => {
386
- const A = record({
387
- A: union([number(0), undefinedType, nullType]),
388
- });
389
-
390
- const B = record({
391
- B: union([number(0), undefinedType, nullType]),
392
- });
393
-
394
- const C = partial(
395
- record({
396
- C: union([number(0), nullType]),
397
- }),
398
- );
399
-
400
- // Case 1: Union validation is predictable and correct
401
- {
402
- const UnionBA = union([B, A]);
403
- const result = UnionBA.validate({ A: 1 });
404
-
405
- expect(Result.isOk(result)).toBe(true);
406
-
407
- if (Result.isOk(result)) {
408
- // No unexpected fields added
409
- expect(result.value).toStrictEqual({ A: 1 });
410
-
411
- // Type guards behave correctly
412
- expect(A.is(result.value)).toBe(true); // Correct
413
- expect(B.is(result.value)).toBe(false); // Correct! B requires field B
414
- }
415
- }
416
-
417
- // Case 2: Consistent validation behavior
418
- {
419
- const UnionCA = union([C, A]);
420
- const result = UnionCA.validate({ A: 1 });
421
-
422
- expect(Result.isOk(result)).toBe(true);
423
-
424
- if (Result.isOk(result)) {
425
- // Correct and consistent result
426
- expect(result.value).toStrictEqual({ A: 1 });
427
-
428
- // Type guards work as expected
429
- expect(A.is(result.value)).toBe(true); // Correct
430
- // Note: In ts-fortress, partial types are more permissive and can accept
431
- // objects with additional fields, so C.is() returns true here.
432
- // This is different from io-ts behavior and shows ts-fortress's
433
- // consistent approach to partial type validation.
434
- expect(C.is(result.value)).toBe(true); // ts-fortress allows extra fields in partial
435
- }
436
- }
437
- });
438
-
439
- test('union validation handles partial types correctly', () => {
440
- const FullRecord = record({
441
- name: number(0),
442
- value: number(0),
443
- });
444
-
445
- const PartialRecord = partial(
446
- record({
447
- name: number(0),
448
- optional: number(0),
449
- }),
450
- );
451
-
452
- const UnionType = union([PartialRecord, FullRecord]);
453
-
454
- // Test with data that matches FullRecord
455
- {
456
- const result = UnionType.validate({ name: 42, value: 100 });
457
- expect(Result.isOk(result)).toBe(true);
458
-
459
- if (Result.isOk(result)) {
460
- expect(result.value).toStrictEqual({ name: 42, value: 100 });
461
- expect(FullRecord.is(result.value)).toBe(true);
462
- // Note: In ts-fortress, partial types accept objects with extra fields
463
- // so PartialRecord.is() returns true even with the 'value' field
464
- expect(PartialRecord.is(result.value)).toBe(true); // ts-fortress partial allows extra fields
465
- }
466
- }
467
-
468
- // Test with data that matches PartialRecord
469
- {
470
- const result = UnionType.validate({ name: 42 });
471
- expect(Result.isOk(result)).toBe(true);
472
-
473
- if (Result.isOk(result)) {
474
- expect(result.value).toStrictEqual({ name: 42 });
475
- expect(FullRecord.is(result.value)).toBe(false); // Missing 'value' field
476
- expect(PartialRecord.is(result.value)).toBe(true);
477
- }
478
- }
479
- });
480
-
481
- test('union validation with complex nested structures', () => {
482
- const TypeA = record({
483
- type: union([undefinedType]), // Only accepts undefined
484
- data: record({
485
- valueA: number(0),
486
- }),
487
- });
488
-
489
- const TypeB = record({
490
- type: nullType, // Only accepts null
491
- data: record({
492
- valueB: number(0),
493
- }),
494
- });
495
-
496
- const UnionAB = union([TypeA, TypeB]);
497
-
498
- // Test TypeA validation
499
- {
500
- const input = {
501
- type: undefined,
502
- data: { valueA: 42 },
503
- };
504
-
505
- const result = UnionAB.validate(input);
506
- expect(Result.isOk(result)).toBe(true);
507
-
508
- if (Result.isOk(result)) {
509
- expect(result.value).toStrictEqual(input);
510
- expect(TypeA.is(result.value)).toBe(true);
511
- expect(TypeB.is(result.value)).toBe(false);
512
- }
513
- }
514
-
515
- // Test TypeB validation
516
- {
517
- const input = {
518
- type: null,
519
- data: { valueB: 99 },
520
- };
521
-
522
- const result = UnionAB.validate(input);
523
- expect(Result.isOk(result)).toBe(true);
524
-
525
- if (Result.isOk(result)) {
526
- expect(result.value).toStrictEqual(input);
527
- expect(TypeA.is(result.value)).toBe(false);
528
- expect(TypeB.is(result.value)).toBe(true);
529
- }
530
- }
531
-
532
- // Test invalid data
533
- {
534
- const input = {
535
- type: 'invalid',
536
- data: { someField: 123 },
537
- };
538
-
539
- const result = UnionAB.validate(input);
540
- expect(Result.isErr(result)).toBe(true);
541
- }
542
- });
543
- });
544
- });