@evolu/common 8.10.0 → 8.11.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.
Files changed (144) hide show
  1. package/dist/src/Config.d.ts +22 -22
  2. package/dist/src/Config.d.ts.map +1 -1
  3. package/dist/src/Console.d.ts +62 -7
  4. package/dist/src/Console.d.ts.map +1 -1
  5. package/dist/src/Console.js +20 -4
  6. package/dist/src/Crypto.d.ts +76 -4
  7. package/dist/src/Crypto.d.ts.map +1 -1
  8. package/dist/src/Crypto.js +55 -4
  9. package/dist/src/Error.d.ts +45 -0
  10. package/dist/src/Error.d.ts.map +1 -1
  11. package/dist/src/Error.js +69 -0
  12. package/dist/src/Fs.d.ts +92 -18
  13. package/dist/src/Fs.d.ts.map +1 -1
  14. package/dist/src/Fs.js +2 -0
  15. package/dist/src/Identicon.d.ts +2 -2
  16. package/dist/src/Identicon.js +2 -2
  17. package/dist/src/LeakDetector.d.ts +22 -3
  18. package/dist/src/LeakDetector.d.ts.map +1 -1
  19. package/dist/src/LeakDetector.js +12 -2
  20. package/dist/src/LockManager.d.ts +8 -0
  21. package/dist/src/LockManager.d.ts.map +1 -1
  22. package/dist/src/LockManager.js +6 -0
  23. package/dist/src/Object.d.ts.map +1 -1
  24. package/dist/src/Object.js +5 -0
  25. package/dist/src/Platform.d.ts +47 -7
  26. package/dist/src/Platform.d.ts.map +1 -1
  27. package/dist/src/Platform.js +24 -5
  28. package/dist/src/Random.d.ts +25 -2
  29. package/dist/src/Random.d.ts.map +1 -1
  30. package/dist/src/Random.js +14 -2
  31. package/dist/src/Resource.d.ts +156 -1
  32. package/dist/src/Resource.d.ts.map +1 -1
  33. package/dist/src/Resource.js +201 -72
  34. package/dist/src/Schedule.d.ts +11 -10
  35. package/dist/src/Schedule.d.ts.map +1 -1
  36. package/dist/src/Schedule.js +1 -1
  37. package/dist/src/Sqlite.d.ts +132 -16
  38. package/dist/src/Sqlite.d.ts.map +1 -1
  39. package/dist/src/Sqlite.js +63 -9
  40. package/dist/src/Task.d.ts +15 -4
  41. package/dist/src/Task.d.ts.map +1 -1
  42. package/dist/src/Task.js +41 -15
  43. package/dist/src/Test.d.ts +9 -0
  44. package/dist/src/Test.d.ts.map +1 -1
  45. package/dist/src/Test.js +4 -0
  46. package/dist/src/Time.d.ts +106 -9
  47. package/dist/src/Time.d.ts.map +1 -1
  48. package/dist/src/Time.js +55 -4
  49. package/dist/src/Type.d.ts +1455 -1310
  50. package/dist/src/Type.d.ts.map +1 -1
  51. package/dist/src/Type.js +1274 -517
  52. package/dist/src/WebSocket.d.ts +164 -13
  53. package/dist/src/WebSocket.d.ts.map +1 -1
  54. package/dist/src/WebSocket.js +133 -24
  55. package/dist/src/Worker.d.ts +90 -8
  56. package/dist/src/Worker.d.ts.map +1 -1
  57. package/dist/src/Worker.js +28 -2
  58. package/dist/src/index.d.ts +6 -7
  59. package/dist/src/index.d.ts.map +1 -1
  60. package/dist/src/index.js +2 -3
  61. package/dist/src/local-first/Db.d.ts +52 -3
  62. package/dist/src/local-first/Db.d.ts.map +1 -1
  63. package/dist/src/local-first/Db.js +412 -137
  64. package/dist/src/local-first/Evolu.d.ts +336 -211
  65. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  66. package/dist/src/local-first/Evolu.js +102 -15
  67. package/dist/src/local-first/Owner.d.ts +13 -30
  68. package/dist/src/local-first/Owner.d.ts.map +1 -1
  69. package/dist/src/local-first/Owner.js +13 -30
  70. package/dist/src/local-first/Protocol.d.ts +94 -16
  71. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  72. package/dist/src/local-first/Protocol.js +118 -38
  73. package/dist/src/local-first/Query.d.ts +8 -15
  74. package/dist/src/local-first/Query.d.ts.map +1 -1
  75. package/dist/src/local-first/Schema.d.ts +335 -21
  76. package/dist/src/local-first/Schema.d.ts.map +1 -1
  77. package/dist/src/local-first/Schema.js +214 -17
  78. package/dist/src/local-first/Shared.d.ts +537 -22
  79. package/dist/src/local-first/Shared.d.ts.map +1 -1
  80. package/dist/src/local-first/Shared.js +1437 -234
  81. package/dist/src/local-first/Storage.d.ts +192 -14
  82. package/dist/src/local-first/Storage.d.ts.map +1 -1
  83. package/dist/src/local-first/Storage.js +81 -20
  84. package/dist/src/local-first/Timestamp.d.ts +392 -41
  85. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  86. package/dist/src/local-first/Timestamp.js +403 -81
  87. package/dist/src/local-first/index.d.ts +0 -1
  88. package/dist/src/local-first/index.d.ts.map +1 -1
  89. package/dist/src/local-first/index.js +0 -1
  90. package/package.json +1 -1
  91. package/src/Assert.test.ts +2 -5
  92. package/src/Config.test.ts +2 -6
  93. package/src/Config.ts +133 -133
  94. package/src/Console.ts +62 -7
  95. package/src/Crypto.ts +76 -4
  96. package/src/Eq.test.ts +2 -3
  97. package/src/Error.test.ts +76 -3
  98. package/src/Error.ts +71 -0
  99. package/src/Fs.ts +92 -18
  100. package/src/Identicon.ts +2 -2
  101. package/src/LeakDetector.ts +22 -3
  102. package/src/LockManager.ts +8 -0
  103. package/src/Object.test.ts +27 -12
  104. package/src/Object.ts +5 -0
  105. package/src/Platform.ts +50 -8
  106. package/src/Random.ts +25 -2
  107. package/src/Resource.test.ts +837 -0
  108. package/src/Resource.ts +235 -15
  109. package/src/Schedule.test.ts +50 -12
  110. package/src/Schedule.ts +24 -14
  111. package/src/Sqlite.ts +137 -17
  112. package/src/Task.test.ts +189 -8
  113. package/src/Task.ts +56 -17
  114. package/src/Test.ts +9 -0
  115. package/src/Time.ts +106 -9
  116. package/src/Type.test.ts +946 -1028
  117. package/src/Type.ts +4195 -3136
  118. package/src/Types.test.ts +4 -14
  119. package/src/WebSocket.ts +313 -40
  120. package/src/Worker.ts +90 -8
  121. package/src/index.ts +15 -6
  122. package/src/local-first/Db.ts +644 -339
  123. package/src/local-first/Evolu.test.ts +686 -21
  124. package/src/local-first/Evolu.ts +450 -228
  125. package/src/local-first/Owner.ts +13 -30
  126. package/src/local-first/Protocol.test.ts +617 -10
  127. package/src/local-first/Protocol.ts +196 -72
  128. package/src/local-first/Query.ts +8 -15
  129. package/src/local-first/Schema.test.ts +143 -0
  130. package/src/local-first/Schema.ts +363 -24
  131. package/src/local-first/Shared.test.ts +7731 -559
  132. package/src/local-first/Shared.ts +2036 -267
  133. package/src/local-first/Storage.ts +218 -32
  134. package/src/local-first/Timestamp.test.ts +344 -70
  135. package/src/local-first/Timestamp.ts +434 -118
  136. package/src/local-first/index.ts +0 -1
  137. package/dist/src/local-first/Error.d.ts +0 -12
  138. package/dist/src/local-first/Error.d.ts.map +0 -1
  139. package/dist/src/local-first/Error.js +0 -6
  140. package/dist/src/local-first/LocalAuth.d.ts +0 -150
  141. package/dist/src/local-first/LocalAuth.d.ts.map +0 -1
  142. package/dist/src/local-first/LocalAuth.js +0 -179
  143. package/src/local-first/Error.ts +0 -17
  144. package/src/local-first/LocalAuth.ts +0 -457
package/src/Type.test.ts CHANGED
@@ -315,6 +315,9 @@ import {
315
315
  type RecordNotRecordError,
316
316
  type RecordType,
317
317
  type RecordValueIssue,
318
+ type RootMapType,
319
+ type RootRecordType,
320
+ type RootTupleType,
318
321
  type SetElementIssue,
319
322
  type SetElementsError,
320
323
  type SetError,
@@ -1171,6 +1174,263 @@ describe("Type operations", () => {
1171
1174
  });
1172
1175
  });
1173
1176
 
1177
+ describe("identity Types", () => {
1178
+ // Transforms returning their input keep the Result-based container paths, so
1179
+ // they show that containers of identity Types validate the same way.
1180
+ const SameString = transform("SameString", String, String, {
1181
+ from: (value) => ok(value),
1182
+ to: (value) => value,
1183
+ });
1184
+ const SameNumber = transform("SameNumber", Number, Number, {
1185
+ from: (value) => ok(value),
1186
+ to: (value) => value,
1187
+ });
1188
+
1189
+ const withProperty = <T extends object>(
1190
+ value: T,
1191
+ key: PropertyKey,
1192
+ descriptor: PropertyDescriptor,
1193
+ ): T => globalThis.Object.defineProperty(value, key, descriptor);
1194
+ const accessor = { get: () => "value", enumerable: true };
1195
+ const nonEnumerable = { value: "value", enumerable: false };
1196
+ const symbol = globalThis.Symbol("key");
1197
+
1198
+ // A Map without own properties whose inherited iterator repeats keys.
1199
+ const setupRepeatedKeyMap = (
1200
+ entries: ReadonlyArray<readonly [unknown, unknown]>,
1201
+ ): ReadonlyMap<unknown, unknown> =>
1202
+ globalThis.Object.create(
1203
+ globalThis.Object.create(Map.prototype, {
1204
+ [globalThis.Symbol.iterator]: { value: () => entries.values() },
1205
+ }) as object,
1206
+ ) as ReadonlyMap<unknown, unknown>;
1207
+
1208
+ const assertSameValidation = (
1209
+ identityType: TypeNode,
1210
+ decodingType: TypeNode,
1211
+ values: ReadonlyArray<unknown>,
1212
+ ): void => {
1213
+ for (const value of values) {
1214
+ for (const options of [
1215
+ { errors: "first" },
1216
+ { errors: "all" },
1217
+ ] satisfies ReadonlyArray<ValidationOptions>) {
1218
+ const result = identityType.fromUnknown(value, options);
1219
+ // Unlike assertEqual, this compares symbol keys of error records.
1220
+ nodeAssert.deepStrictEqual(
1221
+ result,
1222
+ decodingType.fromUnknown(value, options),
1223
+ );
1224
+ if (result.ok) assertSame(result.value, value);
1225
+ }
1226
+ assertSame(identityType.is(value), decodingType.is(value));
1227
+
1228
+ // Output validation of a transform wraps its errors, so only the identity
1229
+ // Type is expected to report its decoding error.
1230
+ const outputError = (type: TypeNode) => {
1231
+ try {
1232
+ assertType(type, value);
1233
+ return undefined;
1234
+ } catch (error) {
1235
+ return (error as Error).cause;
1236
+ }
1237
+ };
1238
+ const result = identityType.fromUnknown(value);
1239
+ nodeAssert.deepStrictEqual(
1240
+ outputError(identityType),
1241
+ result.ok ? undefined : result.error,
1242
+ );
1243
+ assertSame(outputError(decodingType) === undefined, result.ok);
1244
+ }
1245
+ };
1246
+
1247
+ it("validate collections like decoding collections", () => {
1248
+ assertSameValidation(array(String), array(SameString), [
1249
+ ["a", "b"],
1250
+ ["a", 1, "b", 2],
1251
+ globalThis.Object.assign(createMutableArray<unknown>(3), {
1252
+ 0: "a",
1253
+ 2: "b",
1254
+ }),
1255
+ withProperty(["a", "b"], 1, accessor),
1256
+ globalThis.Object.assign(["a"], { extra: 1 }),
1257
+ 1,
1258
+ ]);
1259
+ assertSameValidation(set(String), set(SameString), [
1260
+ new Set(["a", "b"]),
1261
+ new Set(["a", 1, 2]),
1262
+ withProperty(new Set(["a", 1]), "extra", { value: 1 }),
1263
+ globalThis.Object.assign(new Set(["a", 1]), { extra: 1, other: 2 }),
1264
+ 1,
1265
+ ]);
1266
+ assertSameValidation(map(String, Number), map(SameString, SameNumber), [
1267
+ new Map([["a", 1]]),
1268
+ new Map<unknown, unknown>([
1269
+ ["a", 1],
1270
+ [1, "b"],
1271
+ ["c", "d"],
1272
+ ]),
1273
+ withProperty(new Map<unknown, unknown>([[1, "b"]]), "extra", {
1274
+ value: 1,
1275
+ }),
1276
+ globalThis.Object.assign(new Map<unknown, unknown>([[1, "b"]]), {
1277
+ extra: 1,
1278
+ other: 2,
1279
+ }),
1280
+ setupRepeatedKeyMap([
1281
+ ["a", 1],
1282
+ ["a", 2],
1283
+ ]),
1284
+ setupRepeatedKeyMap([
1285
+ [1, 1],
1286
+ [1, 2],
1287
+ ]),
1288
+ setupRepeatedKeyMap([
1289
+ ["a", 1],
1290
+ ["b", "x"],
1291
+ [1, 2],
1292
+ ["a", 2],
1293
+ ]),
1294
+ 1,
1295
+ ]);
1296
+ assertSameValidation(tuple(String, Number), tuple(SameString, SameNumber), [
1297
+ ["a", 1],
1298
+ [1, "b"],
1299
+ ["a"],
1300
+ globalThis.Object.assign(["a", 1], { extra: 1 }),
1301
+ 1,
1302
+ ]);
1303
+ });
1304
+
1305
+ it("reject values without the expected class or tag", () => {
1306
+ class User {
1307
+ readonly name = "Ada";
1308
+ }
1309
+ const UserInstance = instanceOf(User);
1310
+
1311
+ assertFalse(Date.is(1));
1312
+ assertEqual(
1313
+ array(Date).fromUnknown([new globalThis.Date(0), 1], { errors: "all" }),
1314
+ err({
1315
+ type: "Array",
1316
+ reason: {
1317
+ kind: "Items",
1318
+ issues: [
1319
+ {
1320
+ kind: "Element",
1321
+ index: 1,
1322
+ error: { type: "ObjectTag", expected: "Date", value: 1 },
1323
+ },
1324
+ ],
1325
+ },
1326
+ }),
1327
+ );
1328
+ assertEqual(
1329
+ array(UserInstance).fromUnknown([new User(), 1], { errors: "all" }),
1330
+ err({
1331
+ type: "Array",
1332
+ reason: {
1333
+ kind: "Items",
1334
+ issues: [
1335
+ {
1336
+ kind: "Element",
1337
+ index: 1,
1338
+ error: { type: "InstanceOf", constructorName: "User", value: 1 },
1339
+ },
1340
+ ],
1341
+ },
1342
+ }),
1343
+ );
1344
+ });
1345
+
1346
+ it("validate objects and records like decoding ones", () => {
1347
+ const invalidObjects = [
1348
+ 1,
1349
+ globalThis.Object.create({}),
1350
+ {},
1351
+ { a: "x", b: "x", c: 1, [symbol]: 1 },
1352
+ withProperty({}, "a", accessor),
1353
+ withProperty({}, "a", nonEnumerable),
1354
+ ];
1355
+ const invalidRecords = [
1356
+ { a: 1, c: "y", [symbol]: 1 },
1357
+ withProperty({ a: 1 }, "c", accessor),
1358
+ withProperty({ a: 1 }, "c", nonEnumerable),
1359
+ ];
1360
+
1361
+ assertSameValidation(
1362
+ object({ a: Number, b: optional(String) }),
1363
+ object({ a: SameNumber, b: optional(SameString) }),
1364
+ [{ a: 1 }, { a: 1, b: "x" }, { b: "x", a: 1 }, ...invalidObjects],
1365
+ );
1366
+ assertSameValidation(
1367
+ record(String, Number),
1368
+ record(SameString, SameNumber),
1369
+ [{ a: 1 }, new globalThis.Date(0), ...invalidObjects, ...invalidRecords],
1370
+ );
1371
+ for (const decodingType of [
1372
+ object({ a: SameNumber }, record(String, Number)),
1373
+ object({ a: Number }, record(String, SameNumber)),
1374
+ ]) {
1375
+ assertSameValidation(
1376
+ object({ a: Number }, record(String, Number)),
1377
+ decodingType,
1378
+ [{ a: 1, c: 1 }, ...invalidObjects, ...invalidRecords],
1379
+ );
1380
+ }
1381
+ });
1382
+
1383
+ it("copies identity Record properties into a decoded object", () => {
1384
+ const Model = object(
1385
+ { count: setupNumberFromString() },
1386
+ record(String, union(String, Number)),
1387
+ );
1388
+
1389
+ const result = Model.fromUnknown({ count: "1", first: 2, second: "3" });
1390
+
1391
+ assertOk(result, { count: 1, first: 2, second: "3" });
1392
+ assertSame(globalThis.Object.getPrototypeOf(result.value), null);
1393
+ });
1394
+
1395
+ it("validate unions like decoding unions", () => {
1396
+ const Created = object({ type: literal("Created"), name: String });
1397
+ const Deleted = object({ type: literal("Deleted"), id: Number });
1398
+
1399
+ assertSameValidation(
1400
+ union(String, Number, null),
1401
+ union(SameString, SameNumber, null),
1402
+ ["a", 1, null, true],
1403
+ );
1404
+ // Lazy Types have no identity check, so this Union input validates
1405
+ // members with Results.
1406
+ assertSameValidation(
1407
+ union(String, Number).parent,
1408
+ union(
1409
+ lazy(() => String),
1410
+ Number,
1411
+ ).parent,
1412
+ ["a", 1, true],
1413
+ );
1414
+ assertSameValidation(
1415
+ array(discriminatedUnion(Created, Deleted)),
1416
+ array(
1417
+ discriminatedUnion(
1418
+ object({ type: literal("Created"), name: SameString }),
1419
+ Deleted,
1420
+ ),
1421
+ ),
1422
+ [
1423
+ [
1424
+ { type: "Created", name: "Ada" },
1425
+ { type: "Deleted", id: 1 },
1426
+ ],
1427
+ [{ type: "Created", name: 1 }, { type: "Deleted" }, { type: "Moved" }],
1428
+ [1],
1429
+ ],
1430
+ );
1431
+ });
1432
+ });
1433
+
1174
1434
  describe("Type.orThrow", () => {
1175
1435
  it("formats a returned validation error once and preserves its identity", () => {
1176
1436
  const cause = { type: "Text", value: "invalid" } as const;
@@ -1666,6 +1926,27 @@ describe("Standard Schema", () => {
1666
1926
  ],
1667
1927
  });
1668
1928
  });
1929
+
1930
+ it("prefixes nested JsonValue and Data issue paths", async () => {
1931
+ const Model = object({ json: JsonValue, data: array(Data) });
1932
+ const result = await Model["~standard"].validate({
1933
+ json: { values: [globalThis.Number.NaN] },
1934
+ data: [1, { value: /value/u }],
1935
+ });
1936
+
1937
+ assertEqual(result, {
1938
+ issues: [
1939
+ {
1940
+ message: "A JSON number must be finite.",
1941
+ path: ["json", "values", 0],
1942
+ },
1943
+ {
1944
+ message: "A Data Object has an unexpected prototype.",
1945
+ path: ["data", 1, "value"],
1946
+ },
1947
+ ],
1948
+ });
1949
+ });
1669
1950
  });
1670
1951
 
1671
1952
  describe("assertType", () => {
@@ -1675,7 +1956,7 @@ describe("assertType", () => {
1675
1956
  assertType<never, never>();
1676
1957
  assertType<{ readonly value?: string }, { readonly value?: string }>();
1677
1958
 
1678
- const compileTimeAssertions = () => {
1959
+ void (() => {
1679
1960
  // @ts-expect-error ⛔ assertType error: Actual and expected types must be identical
1680
1961
  assertType<"value", string>();
1681
1962
  // @ts-expect-error ⛔ assertType error: Actual and expected types must be identical
@@ -1687,13 +1968,7 @@ describe("assertType", () => {
1687
1968
  { readonly value?: string },
1688
1969
  { readonly value: string | undefined }
1689
1970
  >();
1690
- };
1691
- assertType<
1692
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
1693
- ? true
1694
- : false,
1695
- true
1696
- >();
1971
+ });
1697
1972
  });
1698
1973
 
1699
1974
  it("narrows values that satisfy a Type Output", () => {
@@ -2279,7 +2554,7 @@ describe("localizeTypes", () => {
2279
2554
  "Localized String.",
2280
2555
  );
2281
2556
 
2282
- const compileTimeAssertions = () => {
2557
+ void (() => {
2283
2558
  localizeTypes(
2284
2559
  { Strings },
2285
2560
  {
@@ -2294,14 +2569,7 @@ describe("localizeTypes", () => {
2294
2569
  missingSet: { String: () => "String." },
2295
2570
  },
2296
2571
  );
2297
- };
2298
-
2299
- assertType<
2300
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2301
- ? true
2302
- : false,
2303
- true
2304
- >();
2572
+ });
2305
2573
  });
2306
2574
 
2307
2575
  it("localizes a Union summary and its retained member failures", () => {
@@ -2332,7 +2600,7 @@ describe("localizeTypes", () => {
2332
2600
  "Localized String.",
2333
2601
  );
2334
2602
 
2335
- const compileTimeAssertions = () => {
2603
+ void (() => {
2336
2604
  localizeTypes(
2337
2605
  { Value },
2338
2606
  {
@@ -2340,14 +2608,7 @@ describe("localizeTypes", () => {
2340
2608
  test: { Union: () => "Union." },
2341
2609
  },
2342
2610
  );
2343
- };
2344
-
2345
- assertType<
2346
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2347
- ? true
2348
- : false,
2349
- true
2350
- >();
2611
+ });
2351
2612
  });
2352
2613
 
2353
2614
  it("localizes nested Union details and can localize the result again", async () => {
@@ -2419,7 +2680,7 @@ describe("localizeTypes", () => {
2419
2680
  "Localized Literal.",
2420
2681
  );
2421
2682
 
2422
- const compileTimeAssertions = () => {
2683
+ void (() => {
2423
2684
  localizeTypes(
2424
2685
  { Value },
2425
2686
  {
@@ -2431,14 +2692,7 @@ describe("localizeTypes", () => {
2431
2692
  },
2432
2693
  },
2433
2694
  );
2434
- };
2435
-
2436
- assertType<
2437
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2438
- ? true
2439
- : false,
2440
- true
2441
- >();
2695
+ });
2442
2696
  });
2443
2697
 
2444
2698
  it("localizes fallible members of an infallible Union", () => {
@@ -2458,7 +2712,7 @@ describe("localizeTypes", () => {
2458
2712
  "Localized String.",
2459
2713
  );
2460
2714
 
2461
- const compileTimeAssertions = () => {
2715
+ void (() => {
2462
2716
  localizeTypes(
2463
2717
  { Value },
2464
2718
  {
@@ -2466,14 +2720,7 @@ describe("localizeTypes", () => {
2466
2720
  test: {},
2467
2721
  },
2468
2722
  );
2469
- };
2470
-
2471
- assertType<
2472
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2473
- ? true
2474
- : false,
2475
- true
2476
- >();
2723
+ });
2477
2724
  });
2478
2725
 
2479
2726
  it("requires fallible Types reachable only through reflection", () => {
@@ -2509,7 +2756,7 @@ describe("localizeTypes", () => {
2509
2756
  "Localized String.",
2510
2757
  );
2511
2758
 
2512
- const compileTimeAssertions = () => {
2759
+ void (() => {
2513
2760
  localizeTypes(
2514
2761
  { Model, NonEmptyValues },
2515
2762
  {
@@ -2521,14 +2768,7 @@ describe("localizeTypes", () => {
2521
2768
  },
2522
2769
  },
2523
2770
  );
2524
- };
2525
-
2526
- assertType<
2527
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2528
- ? true
2529
- : false,
2530
- true
2531
- >();
2771
+ });
2532
2772
  });
2533
2773
 
2534
2774
  it("routes DiscriminatedUnion member errors", () => {
@@ -2607,7 +2847,7 @@ describe("localizeTypes", () => {
2607
2847
  },
2608
2848
  ).test.Refined;
2609
2849
  const result = LocalizedRefined.fromUnknown("value");
2610
- const compileTimeAssertions = () => {
2850
+ void (() => {
2611
2851
  localizeTypes(
2612
2852
  { Refined },
2613
2853
  {
@@ -2615,7 +2855,7 @@ describe("localizeTypes", () => {
2615
2855
  test: { String: () => "Localized String." },
2616
2856
  },
2617
2857
  );
2618
- };
2858
+ });
2619
2859
 
2620
2860
  assertErr(result);
2621
2861
  assertEqual(
@@ -2625,12 +2865,6 @@ describe("localizeTypes", () => {
2625
2865
  assertEqual(await LocalizedRefined["~standard"].validate("value"), {
2626
2866
  issues: [{ message: "Localized Refined.", path: [] }],
2627
2867
  });
2628
- assertType<
2629
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2630
- ? true
2631
- : false,
2632
- true
2633
- >();
2634
2868
  });
2635
2869
 
2636
2870
  it("routes custom root TypeOf errors by their expected Types", async () => {
@@ -2837,7 +3071,7 @@ describe("localizeTypes", () => {
2837
3071
  it("requires plain string-keyed maps", () => {
2838
3072
  const selected = globalThis.Symbol("selected");
2839
3073
  const locale = globalThis.Symbol("locale");
2840
- const compileTimeAssertions = () => {
3074
+ void (() => {
2841
3075
  localizeTypes(
2842
3076
  // @ts-expect-error Selected Type names must be strings.
2843
3077
  { [selected]: String },
@@ -2848,7 +3082,7 @@ describe("localizeTypes", () => {
2848
3082
  // @ts-expect-error Locale names must be strings.
2849
3083
  { [locale]: { String: () => "String." } },
2850
3084
  );
2851
- };
3085
+ });
2852
3086
 
2853
3087
  const selectedByName = { [selected]: String } as unknown as {
2854
3088
  readonly String: typeof String;
@@ -2929,13 +3163,6 @@ describe("localizeTypes", () => {
2929
3163
  "localizeTypes maps must be plain objects with own enumerable string-keyed data properties.",
2930
3164
  ),
2931
3165
  );
2932
-
2933
- assertType<
2934
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2935
- ? true
2936
- : false,
2937
- true
2938
- >();
2939
3166
  });
2940
3167
 
2941
3168
  it("requires exactly the reachable formatters", () => {
@@ -2949,7 +3176,7 @@ describe("localizeTypes", () => {
2949
3176
  ...formatters,
2950
3177
  Number: () => "Number.",
2951
3178
  };
2952
- const compileTimeAssertions = () => {
3179
+ void (() => {
2953
3180
  localizeTypes({ Label }, { valid: formatters });
2954
3181
  localizeTypes(
2955
3182
  { Label },
@@ -2976,14 +3203,7 @@ describe("localizeTypes", () => {
2976
3203
  excessStored: excessFormatters,
2977
3204
  },
2978
3205
  );
2979
- };
2980
-
2981
- assertType<
2982
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
2983
- ? true
2984
- : false,
2985
- true
2986
- >();
3206
+ });
2987
3207
  });
2988
3208
 
2989
3209
  it("requires formatters for every union-typed selection branch", () => {
@@ -3015,19 +3235,12 @@ describe("localizeTypes", () => {
3015
3235
  "Localized Number.",
3016
3236
  );
3017
3237
 
3018
- const compileTimeAssertions = (selected: Selected) => {
3238
+ void ((selected: Selected) => {
3019
3239
  localizeTypes(selected, {
3020
3240
  // @ts-expect-error Every possible selection branch requires its formatter.
3021
3241
  test: {},
3022
3242
  });
3023
- };
3024
-
3025
- assertType<
3026
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3027
- ? true
3028
- : false,
3029
- true
3030
- >();
3243
+ });
3031
3244
  });
3032
3245
  });
3033
3246
 
@@ -3114,6 +3327,11 @@ describe("createType", () => {
3114
3327
  NonEmptyString.formatError({ type: "NonEmptyString", value: "" }),
3115
3328
  "Enter some text.",
3116
3329
  );
3330
+ assertAssertionError(
3331
+ () => assertType(NonEmptyString, ""),
3332
+ "Expected NonEmptyString.",
3333
+ { type: "NonEmptyString", value: "" },
3334
+ );
3117
3335
  });
3118
3336
 
3119
3337
  it("asserts that validation callbacks preserve identity", () => {
@@ -3173,7 +3391,7 @@ describe("createType", () => {
3173
3391
  assertEqual(FortyTwo.from(42), ok(42));
3174
3392
  assertType<typeof FortyTwo.Output, 42>();
3175
3393
 
3176
- const compileTimeAssertions = () => {
3394
+ void (() => {
3177
3395
  createType(
3178
3396
  "Length",
3179
3397
  String,
@@ -3197,14 +3415,7 @@ describe("createType", () => {
3197
3415
  // @ts-expect-error An infallible child Type must not provide a formatter.
3198
3416
  () => "Unreachable.",
3199
3417
  );
3200
- };
3201
-
3202
- assertType<
3203
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3204
- ? true
3205
- : false,
3206
- true
3207
- >();
3418
+ });
3208
3419
  });
3209
3420
 
3210
3421
  it("requires a formatter for root and fallible child Types", () => {
@@ -3217,21 +3428,14 @@ describe("createType", () => {
3217
3428
  ): Result<never, ChildWithoutFormatterError> =>
3218
3429
  err({ type: "ChildWithoutFormatter", value });
3219
3430
 
3220
- const compileTimeAssertions = () => {
3431
+ void (() => {
3221
3432
  // @ts-expect-error A root Type must format its validation errors.
3222
3433
  createType("RootWithoutFormatter", (_value): Result<never, TypeError> =>
3223
3434
  err({ type: "RootWithoutFormatter" }),
3224
3435
  );
3225
3436
  // @ts-expect-error A fallible child Type must format its own error.
3226
3437
  createType("ChildWithoutFormatter", String, fromChildWithoutFormatter);
3227
- };
3228
-
3229
- assertType<
3230
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3231
- ? true
3232
- : false,
3233
- true
3234
- >();
3438
+ });
3235
3439
  });
3236
3440
 
3237
3441
  it("inherits the parent formatter when a child is infallible", () => {
@@ -3283,7 +3487,7 @@ describe("createType", () => {
3283
3487
  readonly value: string;
3284
3488
  }
3285
3489
 
3286
- const compileTimeAssertions = () => {
3490
+ void (() => {
3287
3491
  createType(
3288
3492
  "TypeOf",
3289
3493
  // @ts-expect-error A child error type must not duplicate an inherited error type.
@@ -3292,14 +3496,7 @@ describe("createType", () => {
3292
3496
  err({ type: "TypeOf", value }),
3293
3497
  () => "Duplicate TypeOf error.",
3294
3498
  );
3295
- };
3296
-
3297
- assertType<
3298
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3299
- ? true
3300
- : false,
3301
- true
3302
- >();
3499
+ });
3303
3500
  });
3304
3501
 
3305
3502
  it("requires one concrete name for a fallible child Type", () => {
@@ -3314,37 +3511,28 @@ describe("createType", () => {
3314
3511
  err({ type: "A", value });
3315
3512
  const formatError = () => "A error.";
3316
3513
 
3317
- const compileTimeAssertions = () => {
3514
+ void (() => {
3318
3515
  // @ts-expect-error A union does not identify one concrete Type name.
3319
3516
  createType(unionName, String, from, formatError);
3320
3517
  // @ts-expect-error A widened string does not identify one concrete Type name.
3321
3518
  createType(broadName, String, from, formatError);
3322
3519
  // @ts-expect-error A template pattern does not identify one concrete Type name.
3323
3520
  createType(patternedName, String, from, formatError);
3324
- };
3325
-
3326
- assertType<
3327
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3328
- ? true
3329
- : false,
3330
- true
3331
- >();
3521
+ });
3332
3522
  });
3333
3523
 
3334
3524
  it("requires one concrete name for root and infallible child Types", () => {
3335
3525
  const unionName = "A" as "A" | "B";
3336
3526
  const broadName = "A" as Capitalize<string>;
3337
3527
  const patternedName = "A" as `A${string}`;
3338
- const genericCompileTimeAssertion = <Name extends "A" | "B">(
3339
- name: Name,
3340
- ): Name => {
3528
+ void (<Name extends "A" | "B">(name: Name): Name => {
3341
3529
  // @ts-expect-error An unresolved generic root name might be a union.
3342
3530
  createType(name, ok, () => "Generic root error.");
3343
3531
  // @ts-expect-error An unresolved generic child name might be a union.
3344
3532
  createType(name, String, ok);
3345
3533
  return name;
3346
- };
3347
- const compileTimeAssertions = () => {
3534
+ });
3535
+ void (() => {
3348
3536
  // @ts-expect-error A union does not identify one concrete root Type name.
3349
3537
  createType(unionName, ok, () => "Root error.");
3350
3538
  // @ts-expect-error A widened string does not identify one concrete root Type name.
@@ -3357,30 +3545,13 @@ describe("createType", () => {
3357
3545
  createType(broadName, String, ok);
3358
3546
  // @ts-expect-error A template pattern does not identify one concrete child Type name.
3359
3547
  createType(patternedName, String, ok);
3360
- };
3361
-
3362
- assertType<
3363
- typeof genericCompileTimeAssertion extends (
3364
- ...args: Array<never>
3365
- ) => unknown
3366
- ? true
3367
- : false,
3368
- true
3369
- >();
3370
- assertType<
3371
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3372
- ? true
3373
- : false,
3374
- true
3375
- >();
3548
+ });
3376
3549
  });
3377
3550
 
3378
3551
  it("rejects a parent with erased concrete Type information", () => {
3379
3552
  const erased: FormattableTypeNode = brand("ErasedParent", String);
3380
3553
 
3381
- const compileTimeAssertions = <
3382
- Parent extends typeof String | typeof Number,
3383
- >(
3554
+ void (<Parent extends typeof String | typeof Number>(
3384
3555
  parent: Parent,
3385
3556
  ): Parent => {
3386
3557
  // @ts-expect-error A parent must preserve its concrete Type.
@@ -3388,14 +3559,7 @@ describe("createType", () => {
3388
3559
  // @ts-expect-error An unresolved generic parent might be a union.
3389
3560
  createType("GenericChild", parent, ok);
3390
3561
  return parent;
3391
- };
3392
-
3393
- assertType<
3394
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3395
- ? true
3396
- : false,
3397
- true
3398
- >();
3562
+ });
3399
3563
  });
3400
3564
 
3401
3565
  it("requires a child error type matching the child name", () => {
@@ -3403,7 +3567,7 @@ describe("createType", () => {
3403
3567
  readonly value: string;
3404
3568
  }
3405
3569
 
3406
- const compileTimeAssertions = () => {
3570
+ void (() => {
3407
3571
  createType(
3408
3572
  "ChildName",
3409
3573
  String,
@@ -3412,14 +3576,7 @@ describe("createType", () => {
3412
3576
  err({ type: "DifferentName", value }),
3413
3577
  () => "Different name error.",
3414
3578
  );
3415
- };
3416
-
3417
- assertType<
3418
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
3419
- ? true
3420
- : false,
3421
- true
3422
- >();
3579
+ });
3423
3580
  });
3424
3581
 
3425
3582
  describe("Type", () => {
@@ -3691,10 +3848,41 @@ describe("createTypeWithError", () => {
3691
3848
  ]);
3692
3849
  });
3693
3850
 
3851
+ it("maps only invalid values inside structural Types", () => {
3852
+ const mapError = mock.fn((cause: InferErrors<typeof String>) => ({
3853
+ type: "Value" as const,
3854
+ cause,
3855
+ }));
3856
+ const Values = array(
3857
+ createTypeWithError("Value", String, mapError, () => "Invalid value."),
3858
+ );
3859
+ const valid = ["a", "b"];
3860
+
3861
+ assertOk(Values.fromUnknown(valid), valid);
3862
+ assertSame(mapError.mock.callCount(), 0);
3863
+ assertEqual(Values.fromUnknown(["a", 1]), {
3864
+ ok: false,
3865
+ error: {
3866
+ type: "Array",
3867
+ reason: {
3868
+ kind: "Items",
3869
+ issues: [
3870
+ {
3871
+ kind: "Element",
3872
+ index: 1,
3873
+ error: {
3874
+ type: "Value",
3875
+ cause: { type: "TypeOf", expected: "String", value: 1 },
3876
+ },
3877
+ },
3878
+ ],
3879
+ },
3880
+ },
3881
+ });
3882
+ });
3883
+
3694
3884
  it("rejects transforming sources and incompatible error names", () => {
3695
- const compileTimeAssertions = (
3696
- uncertain: typeof String | typeof Number,
3697
- ) => {
3885
+ void ((uncertain: typeof String | typeof Number) => {
3698
3886
  createTypeWithError(
3699
3887
  "Value",
3700
3888
  // @ts-expect-error Source Type must use identity encoding.
@@ -3716,11 +3904,7 @@ describe("createTypeWithError", () => {
3716
3904
  () => ({ type: "Other" as const }),
3717
3905
  () => "Invalid value.",
3718
3906
  );
3719
- };
3720
- assertType<
3721
- typeof compileTimeAssertions,
3722
- (uncertain: typeof String | typeof Number) => void
3723
- >();
3907
+ });
3724
3908
  });
3725
3909
  });
3726
3910
 
@@ -4136,7 +4320,7 @@ describe("transform", () => {
4136
4320
  });
4137
4321
 
4138
4322
  it("requires a formatter exactly when decoding adds an own error", () => {
4139
- const compileTimeAssertions = () => {
4323
+ void (() => {
4140
4324
  interface MissingFormatterError extends TypeError<"MissingFormatter"> {
4141
4325
  readonly value: string;
4142
4326
  }
@@ -4158,18 +4342,11 @@ describe("transform", () => {
4158
4342
  // @ts-expect-error An infallible transformation has no own error to format.
4159
4343
  formatTestTypeError,
4160
4344
  );
4161
- };
4162
-
4163
- assertType<
4164
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4165
- ? true
4166
- : false,
4167
- true
4168
- >();
4345
+ });
4169
4346
  });
4170
4347
 
4171
4348
  it("requires callbacks to return their declared boundary types", () => {
4172
- const compileTimeAssertions = () => {
4349
+ void (() => {
4173
4350
  transform("InvalidOutput", String, Number, {
4174
4351
  // @ts-expect-error A callback must return the output Type Input.
4175
4352
  from: () => ok("not a number"),
@@ -4180,14 +4357,7 @@ describe("transform", () => {
4180
4357
  // @ts-expect-error An encoder must return the parent Type Output.
4181
4358
  to: () => 42,
4182
4359
  });
4183
- };
4184
-
4185
- assertType<
4186
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4187
- ? true
4188
- : false,
4189
- true
4190
- >();
4360
+ });
4191
4361
  });
4192
4362
 
4193
4363
  it("asserts successful decoding callback results", () => {
@@ -4267,8 +4437,10 @@ describe("transform", () => {
4267
4437
  );
4268
4438
  const erased: FormattableTypeNode = PositiveNumber;
4269
4439
 
4270
- const compileTimeAssertions = () => {
4271
- // @ts-expect-error A parent must preserve its concrete Type.
4440
+ void (() => {
4441
+ // An erased parent exposes every error type, so the name check rejects it
4442
+ // before the concrete Type check.
4443
+ // @ts-expect-error Error type must not duplicate an error inherited from the parent Type.
4272
4444
  transform("ErasedParent", erased, Number, {
4273
4445
  from: () => ok(42),
4274
4446
  to: () => 42,
@@ -4278,28 +4450,21 @@ describe("transform", () => {
4278
4450
  from: () => ok(-1),
4279
4451
  to: globalThis.String,
4280
4452
  });
4281
- };
4282
-
4283
- assertType<
4284
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4285
- ? true
4286
- : false,
4287
- true
4288
- >();
4453
+ });
4289
4454
  });
4290
4455
 
4291
4456
  it("rejects unresolved generic parent and output Types", () => {
4292
4457
  const _A = literal("a");
4293
4458
  const _B = literal("b");
4294
4459
 
4295
- const compileTimeAssertions = <
4460
+ void (<
4296
4461
  Parent extends typeof String | typeof Number,
4297
4462
  Output extends typeof _A | typeof _B,
4298
4463
  >(
4299
4464
  parent: Parent,
4300
4465
  output: Output,
4301
4466
  ): readonly [Parent, Output] => {
4302
- // @ts-expect-error An unresolved generic parent might be a union.
4467
+ // @ts-expect-error The name cannot be checked against an unresolved generic parent.
4303
4468
  transform("GenericParent", parent, Number, {
4304
4469
  from: () => ok(1),
4305
4470
  to: () => "1",
@@ -4310,14 +4475,24 @@ describe("transform", () => {
4310
4475
  to: (value) => value,
4311
4476
  });
4312
4477
  return [parent, output];
4313
- };
4478
+ });
4479
+ });
4314
4480
 
4315
- assertType<
4316
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4317
- ? true
4318
- : false,
4319
- true
4320
- >();
4481
+ it("rejects a union of parent Types", () => {
4482
+ const parent = String as typeof String | typeof TrimmedString;
4483
+
4484
+ void (() => {
4485
+ transform(
4486
+ "UnionParent",
4487
+ // @ts-expect-error Parent must be one concrete Type node. Pass a Union Type node instead of a union of Type nodes.
4488
+ parent,
4489
+ Number,
4490
+ {
4491
+ from: () => ok(1),
4492
+ to: () => "1",
4493
+ },
4494
+ );
4495
+ });
4321
4496
  });
4322
4497
 
4323
4498
  it("requires an own error to use the transformation name", () => {
@@ -4325,7 +4500,7 @@ describe("transform", () => {
4325
4500
  readonly value: string;
4326
4501
  }
4327
4502
 
4328
- const compileTimeAssertions = () => {
4503
+ void (() => {
4329
4504
  transform(
4330
4505
  "NumberFromString",
4331
4506
  String,
@@ -4338,14 +4513,7 @@ describe("transform", () => {
4338
4513
  },
4339
4514
  formatTestTypeError,
4340
4515
  );
4341
- };
4342
-
4343
- assertType<
4344
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4345
- ? true
4346
- : false,
4347
- true
4348
- >();
4516
+ });
4349
4517
  });
4350
4518
 
4351
4519
  it("reserves outputError for errors from the output Type", () => {
@@ -4353,7 +4521,7 @@ describe("transform", () => {
4353
4521
  readonly outputError: TypeOfError<"Number">;
4354
4522
  }
4355
4523
 
4356
- const compileTimeAssertions = () => {
4524
+ void (() => {
4357
4525
  transform(
4358
4526
  "NumberFromString",
4359
4527
  String,
@@ -4373,14 +4541,7 @@ describe("transform", () => {
4373
4541
  },
4374
4542
  formatTestTypeError,
4375
4543
  );
4376
- };
4377
-
4378
- assertType<
4379
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4380
- ? true
4381
- : false,
4382
- true
4383
- >();
4544
+ });
4384
4545
  });
4385
4546
 
4386
4547
  it("does not widen its own errors from a broad formatter", () => {
@@ -4587,10 +4748,10 @@ describe("objectTag", () => {
4587
4748
  const fromParentResult = Tagged.from.parent(value);
4588
4749
  const transformedResult = TaggedFromString.fromUnknown("Tagged");
4589
4750
  const wrongTag = new TaggedValue("Other");
4590
- const compileTimeAssertions = () => {
4751
+ void (() => {
4591
4752
  // @ts-expect-error A raw parent Output has no validated object-tag evidence.
4592
4753
  Tagged.to(value);
4593
- };
4754
+ });
4594
4755
 
4595
4756
  assertType<
4596
4757
  typeof Tagged,
@@ -4636,12 +4797,6 @@ describe("objectTag", () => {
4636
4797
  }),
4637
4798
  'A value {"tag":"Other"} does not have the expected object tag "Tagged".',
4638
4799
  );
4639
- assertType<
4640
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4641
- ? true
4642
- : false,
4643
- true
4644
- >();
4645
4800
  });
4646
4801
 
4647
4802
  it("requires one concrete tag name and a Type for custom tags", () => {
@@ -4661,14 +4816,12 @@ describe("objectTag", () => {
4661
4816
  const outputType = TaggedValueInstance as
4662
4817
  typeof TaggedValueInstance | typeof _OtherValueInstance;
4663
4818
  const erasedOutputType: TypeNode = TaggedValueInstance;
4664
- const genericNameAssertion = <Name extends "Tagged" | "Other">(
4665
- name: Name,
4666
- ): Name => {
4819
+ void (<Name extends "Tagged" | "Other">(name: Name): Name => {
4667
4820
  // @ts-expect-error An unresolved generic could be instantiated with a tag union.
4668
4821
  objectTag(name, TaggedValueInstance);
4669
4822
  return name;
4670
- };
4671
- const genericOutputAssertion = <
4823
+ });
4824
+ void (<
4672
4825
  OutputType extends
4673
4826
  typeof TaggedValueInstance | typeof _OtherValueInstance,
4674
4827
  >(
@@ -4677,8 +4830,8 @@ describe("objectTag", () => {
4677
4830
  // @ts-expect-error An unresolved generic could be instantiated with an output Type union.
4678
4831
  objectTag("Tagged", outputType);
4679
4832
  return outputType;
4680
- };
4681
- const compileTimeAssertions = () => {
4833
+ });
4834
+ void (() => {
4682
4835
  // @ts-expect-error A union does not identify one concrete object tag.
4683
4836
  objectTag(unionName, TaggedValueInstance);
4684
4837
  // @ts-expect-error A union does not identify one predefined object tag.
@@ -4695,26 +4848,7 @@ describe("objectTag", () => {
4695
4848
  objectTag("Tagged", outputType);
4696
4849
  // @ts-expect-error The output Type must retain its concrete information.
4697
4850
  objectTag("Tagged", erasedOutputType);
4698
- };
4699
-
4700
- assertType<
4701
- typeof genericNameAssertion extends (...args: Array<never>) => unknown
4702
- ? true
4703
- : false,
4704
- true
4705
- >();
4706
- assertType<
4707
- typeof genericOutputAssertion extends (...args: Array<never>) => unknown
4708
- ? true
4709
- : false,
4710
- true
4711
- >();
4712
- assertType<
4713
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4714
- ? true
4715
- : false,
4716
- true
4717
- >();
4851
+ });
4718
4852
  });
4719
4853
 
4720
4854
  it("rejects an ObjectTag error inherited from the output Type", () => {
@@ -4723,20 +4857,13 @@ describe("objectTag", () => {
4723
4857
  }
4724
4858
 
4725
4859
  const Tagged = objectTag("Tagged", instanceOf(TaggedValue));
4726
- const compileTimeAssertions = () => {
4860
+ void (() => {
4727
4861
  objectTag(
4728
4862
  "Other",
4729
4863
  // @ts-expect-error An ObjectTag error must not duplicate one inherited from the output Type.
4730
4864
  Tagged,
4731
4865
  );
4732
- };
4733
-
4734
- assertType<
4735
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4736
- ? true
4737
- : false,
4738
- true
4739
- >();
4866
+ });
4740
4867
  });
4741
4868
 
4742
4869
  it("infers ObjectTag localization", () => {
@@ -4808,22 +4935,17 @@ describe("instanceOf", () => {
4808
4935
  type ErasedConstructorParameter = Parameters<
4809
4936
  typeof instanceOf<ErasedConstructor>
4810
4937
  >[0];
4811
- const compileTimeAssertions = (
4812
- constructor: Constructor,
4813
- erasedConstructor: ErasedConstructor,
4814
- ) => {
4938
+ void ((constructor: Constructor, erasedConstructor: ErasedConstructor) => {
4815
4939
  // @ts-expect-error An Instance Type requires one concrete constructor.
4816
4940
  instanceOf(constructor);
4817
4941
  // @ts-expect-error An Instance Type requires concrete constructor information.
4818
4942
  instanceOf(erasedConstructor);
4819
- };
4820
- const genericCompileTimeAssertion = <C extends Constructor>(
4821
- constructor: C,
4822
- ): C => {
4943
+ });
4944
+ void (<C extends Constructor>(constructor: C): C => {
4823
4945
  // @ts-expect-error An unresolved generic could be instantiated with a constructor union.
4824
4946
  instanceOf(constructor);
4825
4947
  return constructor;
4826
- };
4948
+ });
4827
4949
 
4828
4950
  assertType<
4829
4951
  Constructor extends ConstructorParameter ? true : false,
@@ -4838,20 +4960,6 @@ describe("instanceOf", () => {
4838
4960
  "⛔ Type error: Constructor must preserve one concrete constructor. Create a Union Type from separate Instance Types instead of passing a union or erased constructor."
4839
4961
  >();
4840
4962
  assertType<ErasedConstructorParameter, ConstructorParameter>();
4841
- assertType<
4842
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
4843
- ? true
4844
- : false,
4845
- true
4846
- >();
4847
- assertType<
4848
- typeof genericCompileTimeAssertion extends (
4849
- ...args: Array<never>
4850
- ) => unknown
4851
- ? true
4852
- : false,
4853
- true
4854
- >();
4855
4963
  });
4856
4964
 
4857
4965
  it("composes multiple constructors through one Union Type", () => {
@@ -4973,11 +5081,10 @@ it("ValidateOutput accepts concrete Types and rejects unions of Type nodes", ()
4973
5081
  assertType<ValidateOutput<typeof String>, typeof String>();
4974
5082
  assertType<ValidateOutput<typeof Value>, typeof Value>();
4975
5083
  const uncertain = String as typeof String | typeof Number;
4976
- const reject = () => {
5084
+ void (() => {
4977
5085
  // @ts-expect-error Output Type must be one concrete Type node. Pass a Union Type node instead of a union of Type nodes.
4978
5086
  defineOutput(uncertain);
4979
- };
4980
- assertType<typeof reject, () => void>();
5087
+ });
4981
5088
  });
4982
5089
 
4983
5090
  describe("literal", () => {
@@ -4993,7 +5100,7 @@ describe("literal", () => {
4993
5100
  prefix: Prefix & ValidateLiteral<Prefix>,
4994
5101
  ): Prefix => prefix;
4995
5102
  assertEqual(definePrefix("APP_"), "APP_");
4996
- const reject = () => {
5103
+ void (() => {
4997
5104
  // @ts-expect-error Expected must be one concrete literal value.
4998
5105
  definePrefix("APP_" as string);
4999
5106
  // @ts-expect-error Expected must be one concrete literal value.
@@ -5002,8 +5109,7 @@ describe("literal", () => {
5002
5109
  definePrefix(TrimmedString.orThrow("APP_"));
5003
5110
  // @ts-expect-error Expected must be one concrete literal value.
5004
5111
  definePrefix("APP_" as `APP_${string}`);
5005
- };
5006
- assertType<typeof reject, () => void>();
5112
+ });
5007
5113
  });
5008
5114
 
5009
5115
  const Hello = literal("Hello");
@@ -5152,7 +5258,7 @@ describe("literal", () => {
5152
5258
  const Amount = brand("Amount", Number);
5153
5259
  const amount = getOrThrow(Amount.from.parent(42));
5154
5260
 
5155
- const compileTimeAssertions = () => {
5261
+ void (() => {
5156
5262
  // @ts-expect-error A widened string does not identify one literal.
5157
5263
  literal(stringValue);
5158
5264
  // @ts-expect-error A widened number does not identify one literal.
@@ -5173,13 +5279,7 @@ describe("literal", () => {
5173
5279
  literal(globalThis.Number.POSITIVE_INFINITY);
5174
5280
  // @ts-expect-error NaN has the widened `number` type.
5175
5281
  literal(globalThis.Number.NaN);
5176
- };
5177
- assertType<
5178
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
5179
- ? true
5180
- : false,
5181
- true
5182
- >();
5282
+ });
5183
5283
  });
5184
5284
 
5185
5285
  describe("Type", () => {
@@ -5831,7 +5931,7 @@ describe("union", () => {
5831
5931
  const uncertain = String as typeof String | typeof Number;
5832
5932
  const possiblyInfallible = String as typeof String | typeof Unknown;
5833
5933
  const erased: FormattableTypeNode = String;
5834
- const compileTimeAssertions = () => {
5934
+ void (() => {
5835
5935
  // @ts-expect-error A member must use one concrete Type node.
5836
5936
  union(uncertain, Boolean).to(42);
5837
5937
  // @ts-expect-error A member must preserve its concrete Type information.
@@ -5842,14 +5942,7 @@ describe("union", () => {
5842
5942
  union("draft", erased).to(true);
5843
5943
  // @ts-expect-error Infallibility must not depend on a runtime member choice.
5844
5944
  union(possiblyInfallible, Number).to(true);
5845
- };
5846
-
5847
- assertType<
5848
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
5849
- ? true
5850
- : false,
5851
- true
5852
- >();
5945
+ });
5853
5946
  });
5854
5947
 
5855
5948
  it("forwards all-errors mode to member Types", () => {
@@ -6253,7 +6346,7 @@ describe("union", () => {
6253
6346
  const stringValue = "draft" as string;
6254
6347
  const unionValue = "draft" as "draft" | "published";
6255
6348
 
6256
- const compileTimeAssertions = () => {
6349
+ void (() => {
6257
6350
  // @ts-expect-error A Union requires at least two member Types.
6258
6351
  union();
6259
6352
  // @ts-expect-error A Union requires at least two member Types.
@@ -6268,14 +6361,7 @@ describe("union", () => {
6268
6361
  union(Number, stringValue);
6269
6362
  // @ts-expect-error A union does not identify one literal.
6270
6363
  union(Number, unionValue);
6271
- };
6272
-
6273
- assertType<
6274
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
6275
- ? true
6276
- : false,
6277
- true
6278
- >();
6364
+ });
6279
6365
  });
6280
6366
  });
6281
6367
 
@@ -6310,19 +6396,12 @@ describe("undefinedOr", () => {
6310
6396
  type Value = typeof String | typeof Number;
6311
6397
  const value = String as Value;
6312
6398
  const erased: FormattableTypeNode = String;
6313
- const compileTimeAssertions = () => {
6399
+ void (() => {
6314
6400
  // @ts-expect-error The supplied Type must use one concrete Type node.
6315
6401
  undefinedOr(value);
6316
6402
  // @ts-expect-error The supplied Type must preserve its concrete information.
6317
6403
  undefinedOr(erased);
6318
- };
6319
-
6320
- assertType<
6321
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
6322
- ? true
6323
- : false,
6324
- true
6325
- >();
6404
+ });
6326
6405
  });
6327
6406
  });
6328
6407
 
@@ -6345,19 +6424,12 @@ describe("nullOr", () => {
6345
6424
  type Value = typeof String | typeof Number;
6346
6425
  const value = String as Value;
6347
6426
  const erased: FormattableTypeNode = String;
6348
- const compileTimeAssertions = () => {
6427
+ void (() => {
6349
6428
  // @ts-expect-error The supplied Type must use one concrete Type node.
6350
6429
  nullOr(value);
6351
6430
  // @ts-expect-error The supplied Type must preserve its concrete information.
6352
6431
  nullOr(erased);
6353
- };
6354
-
6355
- assertType<
6356
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
6357
- ? true
6358
- : false,
6359
- true
6360
- >();
6432
+ });
6361
6433
  });
6362
6434
  });
6363
6435
 
@@ -6380,19 +6452,12 @@ describe("nullishOr", () => {
6380
6452
  type Value = typeof String | typeof Number;
6381
6453
  const value = String as Value;
6382
6454
  const erased: FormattableTypeNode = String;
6383
- const compileTimeAssertions = () => {
6455
+ void (() => {
6384
6456
  // @ts-expect-error The supplied Type must use one concrete Type node.
6385
6457
  nullishOr(value);
6386
6458
  // @ts-expect-error The supplied Type must preserve its concrete information.
6387
6459
  nullishOr(erased);
6388
- };
6389
-
6390
- assertType<
6391
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
6392
- ? true
6393
- : false,
6394
- true
6395
- >();
6460
+ });
6396
6461
  });
6397
6462
  });
6398
6463
 
@@ -6610,14 +6675,13 @@ describe("templateLiteralParser", () => {
6610
6675
  const FixedWidth = union("🙂", "a");
6611
6676
  const VariableWidth = union("🙂", "ab");
6612
6677
  const Value = templateLiteralParser(FixedWidth, String);
6613
- const compileTimeAssertions = () => {
6678
+ void (() => {
6614
6679
  // @ts-expect-error At most one Type capture can have a variable-width string representation.
6615
6680
  templateLiteralParser(VariableWidth, String);
6616
- };
6681
+ });
6617
6682
 
6618
6683
  assertOk(Value.fromUnknown("🙂value"), ["🙂", "value"]);
6619
6684
  assertOk(Value.fromUnknown("avalue"), ["a", "value"]);
6620
- void compileTimeAssertions;
6621
6685
  });
6622
6686
 
6623
6687
  it("rejects surrogate pairs formed across part boundaries", () => {
@@ -6718,14 +6782,13 @@ describe("templateLiteralParser", () => {
6718
6782
  assertFalse(NumberValue.parent.is("number:not-a-number"));
6719
6783
  assertOk(NumberValue.from.parent(encoded), [42]);
6720
6784
 
6721
- const compileTimeAssertions = () => {
6785
+ void (() => {
6722
6786
  // @ts-expect-error A matching string is not necessarily canonical.
6723
6787
  const validLooking: NumberLiteral = "number:42";
6724
6788
  // @ts-expect-error An invalid string is not canonical.
6725
6789
  const invalid: NumberLiteral = "number:not-a-number";
6726
6790
  return [validLooking, invalid];
6727
- };
6728
- void compileTimeAssertions;
6791
+ });
6729
6792
  });
6730
6793
 
6731
6794
  it("distinguishes transforming templates with the same string shape", () => {
@@ -6787,23 +6850,21 @@ describe("templateLiteralParser", () => {
6787
6850
  it("rejects ambiguous variable-width captures statically", () => {
6788
6851
  const VariableUnion = union("a", "bb");
6789
6852
  const Inner = templateLiteralParser("<", String, ">");
6790
- const compileTimeAssertions = () => {
6853
+ void (() => {
6791
6854
  // @ts-expect-error At most one Type capture can have a variable-width string representation.
6792
6855
  templateLiteralParser(String, ":", String);
6793
6856
  // @ts-expect-error At most one Type capture can have a variable-width string representation.
6794
6857
  templateLiteralParser(VariableUnion, String);
6795
6858
  // @ts-expect-error At most one Type capture can have a variable-width string representation.
6796
6859
  templateLiteralParser(Inner, String);
6797
- };
6798
-
6799
- void compileTimeAssertions;
6860
+ });
6800
6861
  });
6801
6862
 
6802
6863
  it("requires a capture and canonically string-encoded concrete parts", () => {
6803
6864
  const widened = "value" as string;
6804
6865
  const uncertain = String as typeof String | typeof Number;
6805
6866
  const parts: ReadonlyArray<typeof String> = [String];
6806
- const compileTimeAssertions = () => {
6867
+ void (() => {
6807
6868
  // @ts-expect-error At least one part must be a Type capture.
6808
6869
  templateLiteralParser("value");
6809
6870
  // @ts-expect-error Part must be a raw string literal or a Type canonically encoded as a string.
@@ -6818,9 +6879,7 @@ describe("templateLiteralParser", () => {
6818
6879
  templateLiteralParser(uncertain);
6819
6880
  // @ts-expect-error Parts must use one concrete finite non-empty tuple.
6820
6881
  templateLiteralParser(...parts);
6821
- };
6822
-
6823
- void compileTimeAssertions;
6882
+ });
6824
6883
  });
6825
6884
 
6826
6885
  it("decodes every capture exactly once", () => {
@@ -7073,13 +7132,12 @@ describe("templateLiteralParser", () => {
7073
7132
  );
7074
7133
  assertEqual(SupportedLocale.to(["en", "US"]), "en-US");
7075
7134
 
7076
- const compileTimeAssertions = () => {
7135
+ void (() => {
7077
7136
  const supported: SupportedLocaleLiteral = "cs-CZ";
7078
7137
  // @ts-expect-error Unsupported language.
7079
7138
  const unsupported: SupportedLocaleLiteral = "fr-CZ";
7080
7139
  return [supported, unsupported];
7081
- };
7082
- void compileTimeAssertions;
7140
+ });
7083
7141
  });
7084
7142
 
7085
7143
  it("normalizes broader capture input into a canonical literal", () => {
@@ -7107,11 +7165,10 @@ describe("templateLiteralParser", () => {
7107
7165
  );
7108
7166
  assertEqual(Tag.to([lowercase]), "tag:evolu");
7109
7167
 
7110
- const compileTimeAssertions = () => {
7168
+ void (() => {
7111
7169
  // @ts-expect-error Encoding requires a lowercase branded Output.
7112
7170
  Tag.to(["EVOLU"]);
7113
- };
7114
- void compileTimeAssertions;
7171
+ });
7115
7172
  });
7116
7173
 
7117
7174
  it("exposes canonical and parsed Standard Schema stages", async () => {
@@ -7196,14 +7253,13 @@ describe("templateLiteral", () => {
7196
7253
  it("uses the same reversible framing rules as templateLiteralParser", () => {
7197
7254
  const Value = templateLiteral(String, "::");
7198
7255
  const Parser = templateLiteralParser(String, "::");
7199
- const compileTimeAssertions = () => {
7256
+ void (() => {
7200
7257
  // @ts-expect-error At most one Type capture can have a variable-width string representation.
7201
7258
  templateLiteral(String, ":", String);
7202
- };
7259
+ });
7203
7260
 
7204
7261
  assertOk(Value.fromUnknown("a::::"), "a::::");
7205
7262
  assertSame(Value.is("a::::"), Parser.parent.is("a::::"));
7206
- void compileTimeAssertions;
7207
7263
  });
7208
7264
  });
7209
7265
 
@@ -7288,21 +7344,76 @@ describe("brand", () => {
7288
7344
  >();
7289
7345
  });
7290
7346
 
7347
+ it("refines decoded values and Outputs of a transformed base", () => {
7348
+ const Positive = brand(
7349
+ "Positive",
7350
+ setupNumberFromString(),
7351
+ (value) => (value > 0 ? ok() : err({ type: "Positive", value })),
7352
+ formatTestTypeError,
7353
+ );
7354
+ const Small = brand(
7355
+ "Small",
7356
+ Positive,
7357
+ (value) => (value < 10 ? ok() : err({ type: "Small", value })),
7358
+ formatTestTypeError,
7359
+ );
7360
+
7361
+ assertOk(Small.fromUnknown("5"), 5);
7362
+ assertEqual(Small.fromUnknown("0"), err({ type: "Positive", value: 0 }));
7363
+ assertEqual(Small.fromUnknown("50"), err({ type: "Small", value: 50 }));
7364
+ assertTrue(Small.is(5));
7365
+ assertFalse(Small.is(50));
7366
+ assertAssertionError(() => assertType(Small, 50), "Expected Small.", {
7367
+ type: "Small",
7368
+ value: 50,
7369
+ });
7370
+ assertAssertionError(() => assertType(Small, "5"), "Expected Small.", {
7371
+ type: "NumberFromString",
7372
+ outputError: { type: "TypeOf", expected: "Number", value: "5" },
7373
+ });
7374
+ });
7375
+
7376
+ it("calls validators with only the value and without a receiver", () => {
7377
+ const receivers = new Set<unknown>();
7378
+ const argumentCounts = new Set<number>();
7379
+ const Small = brand(
7380
+ "Small",
7381
+ Number,
7382
+ function (this: unknown, value, ...rest: ReadonlyArray<unknown>) {
7383
+ receivers.add(this);
7384
+ argumentCounts.add(1 + rest.length);
7385
+ return value < 10 ? ok() : err({ type: "Small", value });
7386
+ },
7387
+ formatTestTypeError,
7388
+ );
7389
+ // A default parameter keeps its default.
7390
+ const SmallEven = brand(
7391
+ "SmallEven",
7392
+ Small,
7393
+ (value, divisor = 2) =>
7394
+ value % divisor === 0 ? ok() : err({ type: "SmallEven", value }),
7395
+ formatTestTypeError,
7396
+ );
7397
+
7398
+ assertOk(Small.fromUnknown(4), 4);
7399
+ assertTrue(Small.is(4));
7400
+ assertOk(SmallEven.fromUnknown(4), 4);
7401
+ assertTrue(SmallEven.is(4));
7402
+ assertEqual(SmallEven.fromUnknown(3), err({ type: "SmallEven", value: 3 }));
7403
+ assertOk(array(SmallEven).fromUnknown([4]), [4]);
7404
+ assertOk(object({ value: SmallEven }).fromUnknown({ value: 4 }), {
7405
+ value: 4,
7406
+ });
7407
+ assertEqual([...receivers], [undefined]);
7408
+ assertEqual([...argumentCounts], [1]);
7409
+ });
7410
+
7291
7411
  it("rejects an unresolved generic infallible name", () => {
7292
- const compileTimeAssertions = <Name extends "A" | "B">(
7293
- name: Name,
7294
- ): Name => {
7412
+ void (<Name extends "A" | "B">(name: Name): Name => {
7295
7413
  // @ts-expect-error An unresolved generic name might be a union.
7296
7414
  brand<Name, typeof String>(name, String);
7297
7415
  return name;
7298
- };
7299
-
7300
- assertType<
7301
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
7302
- ? true
7303
- : false,
7304
- true
7305
- >();
7416
+ });
7306
7417
  });
7307
7418
 
7308
7419
  it("rejects a union of parent Types", () => {
@@ -7321,17 +7432,10 @@ describe("brand", () => {
7321
7432
  it("rejects a parent with erased concrete Type information", () => {
7322
7433
  const erased: FormattableTypeNode = brand("Erased", String);
7323
7434
 
7324
- const compileTimeAssertions = () => {
7435
+ void (() => {
7325
7436
  // @ts-expect-error A parent must preserve its concrete Type.
7326
7437
  brand("Wrapped", erased);
7327
- };
7328
-
7329
- assertType<
7330
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
7331
- ? true
7332
- : false,
7333
- true
7334
- >();
7438
+ });
7335
7439
  });
7336
7440
 
7337
7441
  it("inherits the parent formatter when validation is infallible", () => {
@@ -7351,17 +7455,10 @@ describe("brand", () => {
7351
7455
  ): Result<void, ValidatedWithoutFormatterError> =>
7352
7456
  err({ type: "ValidatedWithoutFormatter", value });
7353
7457
 
7354
- const compileTimeAssertions = () => {
7458
+ void (() => {
7355
7459
  // @ts-expect-error A fallible brand must format its own error.
7356
7460
  brand("ValidatedWithoutFormatter", String, validateWithoutFormatter);
7357
- };
7358
-
7359
- assertType<
7360
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
7361
- ? true
7362
- : false,
7363
- true
7364
- >();
7461
+ });
7365
7462
  });
7366
7463
 
7367
7464
  it("requires one concrete name when validation is fallible", () => {
@@ -7376,21 +7473,14 @@ describe("brand", () => {
7376
7473
  err({ type: "A", value });
7377
7474
  const formatError = () => "A error.";
7378
7475
 
7379
- const compileTimeAssertions = () => {
7476
+ void (() => {
7380
7477
  // @ts-expect-error A union does not identify one concrete Brand name.
7381
7478
  brand(unionName, String, validate, formatError);
7382
7479
  // @ts-expect-error A widened string does not identify one concrete Brand name.
7383
7480
  brand(broadName, String, validate, formatError);
7384
7481
  // @ts-expect-error A template pattern does not identify one concrete Brand name.
7385
7482
  brand(patternedName, String, validate, formatError);
7386
- };
7387
-
7388
- assertType<
7389
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
7390
- ? true
7391
- : false,
7392
- true
7393
- >();
7483
+ });
7394
7484
  });
7395
7485
 
7396
7486
  it("rejects an error type inherited from the parent Type", () => {
@@ -7398,7 +7488,7 @@ describe("brand", () => {
7398
7488
  readonly value: string;
7399
7489
  }
7400
7490
 
7401
- const compileTimeAssertions = () => {
7491
+ void (() => {
7402
7492
  brand(
7403
7493
  "TypeOf",
7404
7494
  // @ts-expect-error A Brand error must not duplicate an inherited error type.
@@ -7407,14 +7497,7 @@ describe("brand", () => {
7407
7497
  err({ type: "TypeOf", value }),
7408
7498
  () => "Duplicate TypeOf error.",
7409
7499
  );
7410
- };
7411
-
7412
- assertType<
7413
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
7414
- ? true
7415
- : false,
7416
- true
7417
- >();
7500
+ });
7418
7501
  });
7419
7502
 
7420
7503
  it("requires a brand error type matching the brand name", () => {
@@ -7422,7 +7505,7 @@ describe("brand", () => {
7422
7505
  readonly value: string;
7423
7506
  }
7424
7507
 
7425
- const compileTimeAssertions = () => {
7508
+ void (() => {
7426
7509
  brand(
7427
7510
  "BrandName",
7428
7511
  String,
@@ -7431,18 +7514,11 @@ describe("brand", () => {
7431
7514
  err({ type: "DifferentName", value }),
7432
7515
  () => "Different name error.",
7433
7516
  );
7434
- };
7435
-
7436
- assertType<
7437
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
7438
- ? true
7439
- : false,
7440
- true
7441
- >();
7517
+ });
7442
7518
  });
7443
7519
 
7444
7520
  it("requires validation to report success without replacing the parent value", () => {
7445
- const compileTimeAssertions = () => {
7521
+ void (() => {
7446
7522
  brand(
7447
7523
  "Lowercase",
7448
7524
  String,
@@ -7450,14 +7526,7 @@ describe("brand", () => {
7450
7526
  (value) => ok(value.toLowerCase()),
7451
7527
  formatTestTypeError,
7452
7528
  );
7453
- };
7454
-
7455
- assertType<
7456
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
7457
- ? true
7458
- : false,
7459
- true
7460
- >();
7529
+ });
7461
7530
  });
7462
7531
 
7463
7532
  it("validates only the brand after a validated Literal parent through from.parent", () => {
@@ -8508,54 +8577,34 @@ describe("BrandFactory", () => {
8508
8577
  type Parent = typeof _NumberFromString | typeof _NumberFromBoolean;
8509
8578
  type ParentParameter = Parameters<typeof positive<Parent>>[0];
8510
8579
 
8511
- const compileTimeAssertions = (parent: Parent) => {
8580
+ void ((parent: Parent) => {
8512
8581
  // @ts-expect-error A Brand Factory requires one concrete parent Type.
8513
8582
  positive(parent);
8514
- };
8583
+ });
8515
8584
 
8516
8585
  assertType<Parent extends ParentParameter ? true : false, false>();
8517
- assertType<
8518
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
8519
- ? true
8520
- : false,
8521
- true
8522
- >();
8523
8586
  });
8524
8587
 
8525
8588
  it("rejects incompatible and erased parents", () => {
8526
8589
  const { nonEmpty } = createNonEmpty();
8527
8590
  const erased: FormattableTypeNode = String;
8528
8591
 
8529
- const compileTimeAssertions = () => {
8592
+ void (() => {
8530
8593
  // @ts-expect-error The parent Output must have a length.
8531
8594
  nonEmpty(Number);
8532
8595
  // @ts-expect-error The parent must preserve its concrete Type information.
8533
8596
  nonEmpty(erased);
8534
- };
8535
-
8536
- assertType<
8537
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
8538
- ? true
8539
- : false,
8540
- true
8541
- >();
8597
+ });
8542
8598
  });
8543
8599
 
8544
8600
  it("rejects a parent that already exposes the factory error type", () => {
8545
8601
  const { nonEmpty } = createNonEmpty();
8546
8602
  const NonEmptyString = nonEmpty(String);
8547
8603
 
8548
- const compileTimeAssertions = () => {
8604
+ void (() => {
8549
8605
  // @ts-expect-error A Brand Factory error must not duplicate an inherited error type.
8550
8606
  nonEmpty(NonEmptyString);
8551
- };
8552
-
8553
- assertType<
8554
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
8555
- ? true
8556
- : false,
8557
- true
8558
- >();
8607
+ });
8559
8608
  });
8560
8609
 
8561
8610
  describe("ValidateBrandFactoryNumber", () => {
@@ -8563,7 +8612,7 @@ describe("BrandFactory", () => {
8563
8612
  const value = globalThis.Number(1);
8564
8613
  const unionValue = 1 as 1 | 2;
8565
8614
  const nonNegativeInt = NonNegativeInt.orThrow(1);
8566
- const compileTimeAssertions = () => {
8615
+ void (() => {
8567
8616
  // @ts-expect-error Numeric Brand parameters must not widen to number.
8568
8617
  minLength(1 + 1);
8569
8618
  // @ts-expect-error Numeric Brand parameters must not be widened.
@@ -8580,14 +8629,7 @@ describe("BrandFactory", () => {
8580
8629
  minLength(unionValue);
8581
8630
  // @ts-expect-error A branded runtime number does not identify one literal.
8582
8631
  maxLength(nonNegativeInt);
8583
- };
8584
-
8585
- assertType<
8586
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
8587
- ? true
8588
- : false,
8589
- true
8590
- >();
8632
+ });
8591
8633
  });
8592
8634
  });
8593
8635
 
@@ -9221,7 +9263,7 @@ describe("BrandFactory", () => {
9221
9263
  const constant = camelCaseToConstantCase(short);
9222
9264
  assertEqual(constant, "A_B_C");
9223
9265
  assertType<typeof constant, ConstantCaseIdentifier>();
9224
- const compileTimeAssertions = () => {
9266
+ void (() => {
9225
9267
  // @ts-expect-error Requires the CamelCaseIdentifier brand.
9226
9268
  camelCaseToPascalCase("example");
9227
9269
  // @ts-expect-error Requires the CamelCaseIdentifier brand.
@@ -9269,8 +9311,7 @@ describe("BrandFactory", () => {
9269
9311
  // @ts-expect-error Uppercase text does not prove the ConstantCaseIdentifier grammar.
9270
9312
  const _constant: ConstantCaseIdentifier =
9271
9313
  "HTTP PORT" as Uppercase<string>;
9272
- };
9273
- assertType<typeof compileTimeAssertions, () => void>();
9314
+ });
9274
9315
  });
9275
9316
  });
9276
9317
 
@@ -9416,7 +9457,7 @@ describe("BrandFactory", () => {
9416
9457
  const unionPrefix = "APP_" as "APP_" | "OTHER_";
9417
9458
  const branded = TrimmedString.orThrow("APP_");
9418
9459
  const templatePrefix = "APP_" as `APP_${string}`;
9419
- const compileTimeAssertions = () => {
9460
+ void (() => {
9420
9461
  // @ts-expect-error Expected must be one concrete literal value.
9421
9462
  startsWith(widened);
9422
9463
  // @ts-expect-error Expected must be one concrete literal value.
@@ -9431,16 +9472,7 @@ describe("BrandFactory", () => {
9431
9472
  startsWith("APP_")(AppName);
9432
9473
  // @ts-expect-error OTHER_ values do not carry the StartsWithAPP_ brand.
9433
9474
  AppName.from(otherName);
9434
- };
9435
-
9436
- assertType<
9437
- typeof compileTimeAssertions extends (
9438
- ...args: Array<never>
9439
- ) => unknown
9440
- ? true
9441
- : false,
9442
- true
9443
- >();
9475
+ });
9444
9476
  });
9445
9477
  });
9446
9478
 
@@ -9604,7 +9636,7 @@ describe("BrandFactory", () => {
9604
9636
  value === "PORT" ? ok(value) : err({ type: "LiteralRoot" }),
9605
9637
  () => "Expected PORT.",
9606
9638
  );
9607
- const compileTimeAssertions = () => {
9639
+ void (() => {
9608
9640
  // @ts-expect-error Expected must be one concrete literal value.
9609
9641
  prefixed(widened);
9610
9642
  // @ts-expect-error Expected must be one concrete literal value.
@@ -9625,15 +9657,7 @@ describe("BrandFactory", () => {
9625
9657
  Setting.from.parent("port:4000");
9626
9658
  // @ts-expect-error Encoding requires a validated Port, not a plain number.
9627
9659
  Setting.to(4000);
9628
- };
9629
- assertType<
9630
- typeof compileTimeAssertions extends (
9631
- ...args: Array<never>
9632
- ) => unknown
9633
- ? true
9634
- : false,
9635
- true
9636
- >();
9660
+ });
9637
9661
  });
9638
9662
  });
9639
9663
 
@@ -9663,19 +9687,10 @@ describe("BrandFactory", () => {
9663
9687
  });
9664
9688
 
9665
9689
  it("returns a Brand Factory that accepts the parent separately", () => {
9666
- const compileTimeAssertions = () => {
9690
+ void (() => {
9667
9691
  // @ts-expect-error Parameterized Brand Factories accept their parent separately.
9668
9692
  minLength(1, String);
9669
- };
9670
-
9671
- assertType<
9672
- typeof compileTimeAssertions extends (
9673
- ...args: Array<never>
9674
- ) => unknown
9675
- ? true
9676
- : false,
9677
- true
9678
- >();
9693
+ });
9679
9694
  });
9680
9695
 
9681
9696
  describe("Type", () => {
@@ -9732,19 +9747,10 @@ describe("BrandFactory", () => {
9732
9747
  });
9733
9748
 
9734
9749
  it("requires a parent value with a length", () => {
9735
- const compileTimeAssertions = () => {
9750
+ void (() => {
9736
9751
  // @ts-expect-error Length constraints require a value with a length.
9737
9752
  maxLength(1)(Number);
9738
- };
9739
-
9740
- assertType<
9741
- typeof compileTimeAssertions extends (
9742
- ...args: Array<never>
9743
- ) => unknown
9744
- ? true
9745
- : false,
9746
- true
9747
- >();
9753
+ });
9748
9754
  });
9749
9755
 
9750
9756
  describe("Type", () => {
@@ -9847,19 +9853,10 @@ describe("BrandFactory", () => {
9847
9853
 
9848
9854
  it("requires one concrete parent Type", () => {
9849
9855
  const parent = String as typeof String | typeof Number;
9850
- const compileTimeAssertions = () => {
9856
+ void (() => {
9851
9857
  // @ts-expect-error A constraint requires one concrete parent Type.
9852
9858
  length(1)(parent);
9853
- };
9854
-
9855
- assertType<
9856
- typeof compileTimeAssertions extends (
9857
- ...args: Array<never>
9858
- ) => unknown
9859
- ? true
9860
- : false,
9861
- true
9862
- >();
9859
+ });
9863
9860
  });
9864
9861
  });
9865
9862
 
@@ -9868,23 +9865,14 @@ describe("BrandFactory", () => {
9868
9865
  const unionName = "Pattern" as "Pattern" | "Other";
9869
9866
  const broadName = "Pattern" as TypeName;
9870
9867
  const patternedName = "Pattern" as `Pattern${string}`;
9871
- const compileTimeAssertions = () => {
9868
+ void (() => {
9872
9869
  // @ts-expect-error A union does not identify one concrete Regex name.
9873
9870
  regex(unionName, /./u);
9874
9871
  // @ts-expect-error A widened string does not identify one concrete Regex name.
9875
9872
  regex(broadName, /./u);
9876
9873
  // @ts-expect-error A template pattern does not identify one concrete Regex name.
9877
9874
  regex(patternedName, /./u);
9878
- };
9879
-
9880
- assertType<
9881
- typeof compileTimeAssertions extends (
9882
- ...args: Array<never>
9883
- ) => unknown
9884
- ? true
9885
- : false,
9886
- true
9887
- >();
9875
+ });
9888
9876
  });
9889
9877
 
9890
9878
  it("keeps stateful matching private and returns immutable pattern data", () => {
@@ -9927,37 +9915,19 @@ describe("BrandFactory", () => {
9927
9915
  assertType<typeof failure.error.source, string>();
9928
9916
  assertType<typeof failure.error.flags, string>();
9929
9917
 
9930
- const compileTimeAssertions = () => {
9918
+ void (() => {
9931
9919
  // @ts-expect-error Regex errors do not expose the live matcher.
9932
9920
  failure.error.pattern.test = () => true; // oxlint-disable-line typescript/no-unsafe-member-access -- The unavailable matcher access is intentionally rejected above.
9933
9921
  // @ts-expect-error Pattern data is readonly.
9934
9922
  failure.error.source = ".*";
9935
- };
9936
-
9937
- assertType<
9938
- typeof compileTimeAssertions extends (
9939
- ...args: Array<never>
9940
- ) => unknown
9941
- ? true
9942
- : false,
9943
- true
9944
- >();
9923
+ });
9945
9924
  });
9946
9925
 
9947
9926
  it("requires a string parent Output", () => {
9948
- const compileTimeAssertions = () => {
9927
+ void (() => {
9949
9928
  // @ts-expect-error Regex constraints require string Outputs.
9950
9929
  regex("NumberPattern", /1/u)(Number);
9951
- };
9952
-
9953
- assertType<
9954
- typeof compileTimeAssertions extends (
9955
- ...args: Array<never>
9956
- ) => unknown
9957
- ? true
9958
- : false,
9959
- true
9960
- >();
9930
+ });
9961
9931
  });
9962
9932
 
9963
9933
  describe("Type", () => {
@@ -10124,15 +10094,13 @@ describe("BrandFactory", () => {
10124
10094
  const _unionBrand = "Todo" as "Todo" | "User";
10125
10095
  const _broadBrand = "Todo" as string;
10126
10096
  const _patternedBrand = "Todo" as `Todo${string}`;
10127
- const genericBrandAssertion = <B extends "Todo" | "User">(
10128
- brand: B,
10129
- ): B => {
10097
+ void (<B extends "Todo" | "User">(brand: B): B => {
10130
10098
  // @ts-expect-error An unresolved generic brand might be a union.
10131
10099
  createId<B>(deps);
10132
10100
  return brand;
10133
- };
10101
+ });
10134
10102
 
10135
- const compileTimeAssertions = () => {
10103
+ void (() => {
10136
10104
  // @ts-expect-error A union would assign multiple brands to one Id.
10137
10105
  createId<typeof _unionBrand>(deps);
10138
10106
  // @ts-expect-error Every Id creator rejects union brands.
@@ -10147,24 +10115,7 @@ describe("BrandFactory", () => {
10147
10115
  const _todoId: Id & Brand<"Todo"> = random;
10148
10116
  // @ts-expect-error A Todo Id must not satisfy a User Id API.
10149
10117
  const _userId: Id & Brand<"User"> = todoRandom;
10150
- };
10151
-
10152
- assertType<
10153
- typeof genericBrandAssertion extends (
10154
- ...args: Array<never>
10155
- ) => unknown
10156
- ? true
10157
- : false,
10158
- true
10159
- >();
10160
- assertType<
10161
- typeof compileTimeAssertions extends (
10162
- ...args: Array<never>
10163
- ) => unknown
10164
- ? true
10165
- : false,
10166
- true
10167
- >();
10118
+ });
10168
10119
  });
10169
10120
 
10170
10121
  it("validates the encoded representation", () => {
@@ -10210,57 +10161,29 @@ describe("BrandFactory", () => {
10210
10161
  assertType<typeof TodoId.Error, TableIdError<"Todo">>();
10211
10162
  assertType<typeof value, Id & Brand<"Todo">>();
10212
10163
 
10213
- const compileTimeAssertions = () => {
10214
- // @ts-expect-error A Todo Id must not satisfy a User Id API.
10215
- const _userId: Id & Brand<"User"> = value;
10216
- };
10217
-
10218
- assertType<
10219
- typeof compileTimeAssertions extends (
10220
- ...args: Array<never>
10221
- ) => unknown
10222
- ? true
10223
- : false,
10224
- true
10225
- >();
10164
+ void (() => {
10165
+ // @ts-expect-error A Todo Id must not satisfy a User Id API.
10166
+ const _userId: Id & Brand<"User"> = value;
10167
+ });
10226
10168
  });
10227
10169
 
10228
10170
  it("requires one concrete table name", () => {
10229
10171
  const unionTable = "Todo" as "Todo" | "User";
10230
10172
  const broadTable = "Todo" as TypeName;
10231
10173
  const patternedTable = "Todo" as `Todo${string}`;
10232
- const genericTableAssertion = <Table extends "Todo" | "User">(
10233
- table: Table,
10234
- ): Table => {
10174
+ void (<Table extends "Todo" | "User">(table: Table): Table => {
10235
10175
  // @ts-expect-error An unresolved generic table might be a union.
10236
10176
  id(table);
10237
10177
  return table;
10238
- };
10239
- const compileTimeAssertions = () => {
10178
+ });
10179
+ void (() => {
10240
10180
  // @ts-expect-error A union would assign multiple table brands to one Id.
10241
10181
  id(unionTable);
10242
10182
  // @ts-expect-error A widened TypeName does not identify one table.
10243
10183
  id(broadTable);
10244
10184
  // @ts-expect-error A template pattern does not identify one table.
10245
10185
  id(patternedTable);
10246
- };
10247
-
10248
- assertType<
10249
- typeof genericTableAssertion extends (
10250
- ...args: Array<never>
10251
- ) => unknown
10252
- ? true
10253
- : false,
10254
- true
10255
- >();
10256
- assertType<
10257
- typeof compileTimeAssertions extends (
10258
- ...args: Array<never>
10259
- ) => unknown
10260
- ? true
10261
- : false,
10262
- true
10263
- >();
10186
+ });
10264
10187
  });
10265
10188
 
10266
10189
  it("converts to and from its 16-byte representation", () => {
@@ -10621,19 +10544,10 @@ describe("BrandFactory", () => {
10621
10544
  });
10622
10545
 
10623
10546
  it("requires a number parent Output", () => {
10624
- const compileTimeAssertions = () => {
10547
+ void (() => {
10625
10548
  // @ts-expect-error Numeric constraints require number Outputs.
10626
10549
  lessThan(1)(String);
10627
- };
10628
-
10629
- assertType<
10630
- typeof compileTimeAssertions extends (
10631
- ...args: Array<never>
10632
- ) => unknown
10633
- ? true
10634
- : false,
10635
- true
10636
- >();
10550
+ });
10637
10551
  });
10638
10552
  });
10639
10553
 
@@ -11015,19 +10929,10 @@ describe("BrandFactory", () => {
11015
10929
  });
11016
10930
 
11017
10931
  it("requires a DecimalString parent", () => {
11018
- const compileTimeAssertions = () => {
10932
+ void (() => {
11019
10933
  // @ts-expect-error The parent must output DecimalString.
11020
10934
  nonNegativeDecimalString(String);
11021
- };
11022
-
11023
- assertType<
11024
- typeof compileTimeAssertions extends (
11025
- ...args: Array<never>
11026
- ) => unknown
11027
- ? true
11028
- : false,
11029
- true
11030
- >();
10935
+ });
11031
10936
  });
11032
10937
 
11033
10938
  describe("Type", () => {
@@ -11244,7 +11149,7 @@ describe("BrandFactory", () => {
11244
11149
  const value = globalThis.String("0.1");
11245
11150
  const unionValue = "0.1" as "0.1" | "0.2";
11246
11151
  const positiveDecimalString = PositiveDecimalString.orThrow("0.1");
11247
- const compileTimeAssertions = () => {
11152
+ void (() => {
11248
11153
  // @ts-expect-error The divisor must be an exact decimal string.
11249
11154
  multipleOf(0.1);
11250
11155
  // @ts-expect-error Arithmetic expressions are numbers, not exact decimal strings.
@@ -11263,16 +11168,7 @@ describe("BrandFactory", () => {
11263
11168
  multipleOf(unionValue);
11264
11169
  // @ts-expect-error A validated runtime string still has no literal value.
11265
11170
  multipleOf(positiveDecimalString);
11266
- };
11267
-
11268
- assertType<
11269
- typeof compileTimeAssertions extends (
11270
- ...args: Array<never>
11271
- ) => unknown
11272
- ? true
11273
- : false,
11274
- true
11275
- >();
11171
+ });
11276
11172
  });
11277
11173
 
11278
11174
  it("creates a Brand Factory requiring an exact multiple", () => {
@@ -11384,19 +11280,10 @@ describe("BrandFactory", () => {
11384
11280
  });
11385
11281
 
11386
11282
  it("returns a Brand Factory that accepts the parent separately", () => {
11387
- const compileTimeAssertions = () => {
11283
+ void (() => {
11388
11284
  // @ts-expect-error Parameterized Brand Factories accept their parent separately.
11389
11285
  between(1, 2, Number);
11390
- };
11391
-
11392
- assertType<
11393
- typeof compileTimeAssertions extends (
11394
- ...args: Array<never>
11395
- ) => unknown
11396
- ? true
11397
- : false,
11398
- true
11399
- >();
11286
+ });
11400
11287
  });
11401
11288
  });
11402
11289
  });
@@ -11527,6 +11414,66 @@ describe("array", () => {
11527
11414
  assertSame(array(array(Number)), array(array(Number)));
11528
11415
  });
11529
11416
 
11417
+ it("reuses Array and Set Types of a frozen element Type", () => {
11418
+ const Frozen = globalThis.Object.freeze(brand("Frozen", String));
11419
+ const Frozens = array(Frozen);
11420
+
11421
+ assertSame(array(Frozen), Frozens);
11422
+ assertSame(Frozens.element, Frozen);
11423
+ assertSame(set(Frozen), set(Frozen));
11424
+ assertOk(Frozens.fromUnknown(["a"]), ["a"]);
11425
+ });
11426
+
11427
+ it("creates Array and Set Types of copied element Types", () => {
11428
+ const Label = brand("Label", String);
11429
+ const Labels = array(Label);
11430
+ const LabelSet = set(Label);
11431
+ const copies = [
11432
+ { ...Label },
11433
+ globalThis.Object.freeze({ ...Label }),
11434
+ globalThis.Object.create(Label) as typeof Label,
11435
+ ];
11436
+
11437
+ for (const copy of copies) {
11438
+ const Copies = array(copy);
11439
+ assertFalse(globalThis.Object.is(Copies, Labels));
11440
+ assertSame(Copies.element, copy);
11441
+ assertSame(array(copy), Copies);
11442
+ assertSame(set(copy).element, copy);
11443
+ assertSame(set(copy), set(copy));
11444
+ }
11445
+ assertSame(array(Label), Labels);
11446
+ assertSame(set(Label), LabelSet);
11447
+ });
11448
+
11449
+ it("keeps cached Collection Types out of localized element Types", () => {
11450
+ const Label = minLength(1)(String);
11451
+ const Labels = array(Label);
11452
+ set(Label);
11453
+ const LocalizedLabel = localizeTypes(
11454
+ { Label },
11455
+ {
11456
+ test: {
11457
+ MinLength1: () => "Localized MinLength1.",
11458
+ String: () => "Localized String.",
11459
+ },
11460
+ },
11461
+ ).test.Label;
11462
+ const LocalizedLabels = array(LocalizedLabel);
11463
+
11464
+ assertFalse(globalThis.Object.is(LocalizedLabels, Labels));
11465
+ assertSame(LocalizedLabels.element, LocalizedLabel);
11466
+ assertSame(array(LocalizedLabel), LocalizedLabels);
11467
+ assertSame(set(LocalizedLabel).element, LocalizedLabel);
11468
+
11469
+ const result = LocalizedLabels.fromUnknown(null);
11470
+ assertErr(result);
11471
+ assertEqual(
11472
+ LocalizedLabels.formatError(result.error),
11473
+ "A value null is not an array.",
11474
+ );
11475
+ });
11476
+
11530
11477
  it("allows heterogeneous element issues in one error", () => {
11531
11478
  interface AError extends TypeError<"A"> {
11532
11479
  readonly value: number;
@@ -11573,38 +11520,22 @@ describe("array", () => {
11573
11520
  });
11574
11521
 
11575
11522
  it("rejects an unresolved generic element Type", () => {
11576
- const compileTimeAssertions = <
11577
- Element extends typeof String | typeof Number,
11578
- >(
11523
+ void (<Element extends typeof String | typeof Number>(
11579
11524
  element: Element,
11580
11525
  ): Element => {
11581
11526
  // @ts-expect-error An unresolved generic element might be a union.
11582
11527
  array(element);
11583
11528
  return element;
11584
- };
11585
-
11586
- assertType<
11587
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
11588
- ? true
11589
- : false,
11590
- true
11591
- >();
11529
+ });
11592
11530
  });
11593
11531
 
11594
11532
  it("rejects an element with erased concrete Type information", () => {
11595
11533
  const erased: FormattableTypeNode = brand("Erased", String);
11596
11534
 
11597
- const compileTimeAssertions = () => {
11535
+ void (() => {
11598
11536
  // @ts-expect-error An element must preserve its concrete Type.
11599
11537
  array(erased);
11600
- };
11601
-
11602
- assertType<
11603
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
11604
- ? true
11605
- : false,
11606
- true
11607
- >();
11538
+ });
11608
11539
  });
11609
11540
  });
11610
11541
 
@@ -11775,6 +11706,35 @@ describe("array", () => {
11775
11706
  assertEqual(reads, 0);
11776
11707
  });
11777
11708
 
11709
+ it("rejects index-like keys that are not canonical indices below the length", () => {
11710
+ const Numbers = array(Number);
11711
+ const keys = [
11712
+ "",
11713
+ "01",
11714
+ "-0",
11715
+ "1.0",
11716
+ "4294967295",
11717
+ "4294967296",
11718
+ "12345678901",
11719
+ ];
11720
+ const value = globalThis.Object.assign(
11721
+ [1],
11722
+ globalThis.Object.fromEntries(keys.map((key) => [key, 1])),
11723
+ );
11724
+
11725
+ assertFalse(Numbers.is(value));
11726
+ assertEqual(
11727
+ Numbers.fromUnknown(value, { errors: "all" }),
11728
+ err({
11729
+ type: "Array",
11730
+ reason: {
11731
+ kind: "Items",
11732
+ issues: keys.map((key) => ({ kind: "ExcessProperty", key })),
11733
+ },
11734
+ }),
11735
+ );
11736
+ });
11737
+
11778
11738
  it("accepts ordinary Record elements through typed operations", () => {
11779
11739
  const Values = array(record(String, Number));
11780
11740
  const input = [{ value: 1 }];
@@ -12029,18 +11989,12 @@ describe("array", () => {
12029
11989
  assertType<Parameters<typeof UserIds.is>, [unknown]>();
12030
11990
  assertType<Parameters<typeof UserIds.orNull>, [ReadonlyArray<number>]>();
12031
11991
 
12032
- const compileTimeAssertions = () => {
11992
+ void (() => {
12033
11993
  // @ts-expect-error Error collection is not observable through `is`.
12034
11994
  UserIds.is([], { errors: "all" });
12035
11995
  // @ts-expect-error Error collection is not observable through `orNull`.
12036
11996
  UserIds.orNull([], { errors: "all" });
12037
- };
12038
- assertType<
12039
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
12040
- ? true
12041
- : false,
12042
- true
12043
- >();
11997
+ });
12044
11998
  });
12045
11999
 
12046
12000
  describe("is", () => {
@@ -13165,18 +13119,12 @@ describe("set", () => {
13165
13119
 
13166
13120
  const uncertain = Math.random() ? String : Number;
13167
13121
  const erased: FormattableTypeNode = String;
13168
- const compileTimeAssertions = () => {
13122
+ void (() => {
13169
13123
  // @ts-expect-error An element must use one concrete Type node.
13170
13124
  set(uncertain);
13171
13125
  // @ts-expect-error An element must preserve its concrete Type.
13172
13126
  set(erased);
13173
- };
13174
- assertType<
13175
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
13176
- ? true
13177
- : false,
13178
- true
13179
- >();
13127
+ });
13180
13128
  });
13181
13129
 
13182
13130
  it("validates the Set boundary and elements", () => {
@@ -13362,7 +13310,7 @@ describe("map", () => {
13362
13310
 
13363
13311
  const uncertain = Math.random() ? String : Number;
13364
13312
  const erased: FormattableTypeNode = String;
13365
- const compileTimeAssertions = () => {
13313
+ void (() => {
13366
13314
  // @ts-expect-error Map key must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.
13367
13315
  map(uncertain, Number);
13368
13316
  // @ts-expect-error Map value must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.
@@ -13371,13 +13319,7 @@ describe("map", () => {
13371
13319
  map(erased, Number);
13372
13320
  // @ts-expect-error A value must preserve its concrete Type.
13373
13321
  map(String, erased);
13374
- };
13375
- assertType<
13376
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
13377
- ? true
13378
- : false,
13379
- true
13380
- >();
13322
+ });
13381
13323
  });
13382
13324
 
13383
13325
  it("validates the Map boundary, structure, keys, and values", () => {
@@ -13515,6 +13457,10 @@ describe("map", () => {
13515
13457
  assertTrue(Counts.is(output));
13516
13458
  assertFalse(Counts.is(input));
13517
13459
  assertSame(Counts.parent, map(String, String));
13460
+ assertType<
13461
+ typeof Counts.parent,
13462
+ RootMapType<typeof String, typeof String>
13463
+ >();
13518
13464
  assertOk(Counts.from.parent(input), output);
13519
13465
  assertType<
13520
13466
  typeof Counts,
@@ -13538,6 +13484,15 @@ describe("map", () => {
13538
13484
  assertSame(map(String, TransparentNumber).to(unchanged), unchanged);
13539
13485
  });
13540
13486
 
13487
+ it("keeps the parent chain finite for widened keys and values", () => {
13488
+ const createLazyMap = (element: AnyType) =>
13489
+ lazy(() => map(element, element));
13490
+ const Names = createLazyMap(String);
13491
+ const names = new Map([["Ada", "Lovelace"]]);
13492
+
13493
+ assertOk(Names.fromUnknown(names), names);
13494
+ });
13495
+
13541
13496
  it("rejects decoded key collisions and invalid encoding collisions", () => {
13542
13497
  const NumberFromString = setupNumberFromString();
13543
13498
  const Counts = map(NumberFromString, Number);
@@ -13757,7 +13712,7 @@ describe("map", () => {
13757
13712
  assertEqual(formatError(new Map([["Ada", "bad"]])), "Localized Number.");
13758
13713
  assertEqual(formatError(null), "Localized Map.");
13759
13714
 
13760
- const compileTimeAssertions = () => {
13715
+ void (() => {
13761
13716
  localizeTypes(
13762
13717
  { Scores },
13763
13718
  {
@@ -13788,14 +13743,7 @@ describe("map", () => {
13788
13743
  },
13789
13744
  },
13790
13745
  );
13791
- };
13792
-
13793
- assertType<
13794
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
13795
- ? true
13796
- : false,
13797
- true
13798
- >();
13746
+ });
13799
13747
  });
13800
13748
  });
13801
13749
 
@@ -13833,6 +13781,10 @@ describe("tuple", () => {
13833
13781
  readonly [typeof String, typeof NumberFromString, typeof Positive]
13834
13782
  >
13835
13783
  >();
13784
+ assertType<
13785
+ typeof Entry.parent,
13786
+ RootTupleType<readonly [typeof String, typeof String, typeof Number]>
13787
+ >();
13836
13788
  assertType<typeof Entry.Input, readonly [string, string, number]>();
13837
13789
  assertType<
13838
13790
  typeof Entry.Output,
@@ -13853,6 +13805,13 @@ describe("tuple", () => {
13853
13805
  >();
13854
13806
  });
13855
13807
 
13808
+ it("keeps the parent chain finite for widened elements", () => {
13809
+ const createLazyTuple = (element: AnyType) => lazy(() => tuple(element));
13810
+ const Names = createLazyTuple(String);
13811
+
13812
+ assertOk(Names.fromUnknown(["Ada"]), ["Ada"]);
13813
+ });
13814
+
13856
13815
  it("creates a root Tuple without a parent", () => {
13857
13816
  const Pair = tuple(String, Number);
13858
13817
 
@@ -13902,16 +13861,14 @@ describe("tuple", () => {
13902
13861
  const uncertain: FormattableTypeNode = String;
13903
13862
  const widened: NonEmptyReadonlyArray<typeof String> = [String];
13904
13863
 
13905
- const validateUnionElement = <
13906
- Element extends typeof String | typeof Number,
13907
- >(
13864
+ void (<Element extends typeof String | typeof Number>(
13908
13865
  element: Element,
13909
13866
  ): Element => {
13910
13867
  // @ts-expect-error An unresolved element might be a union of Types.
13911
13868
  tuple(element);
13912
13869
  return element;
13913
- };
13914
- const validateTupleSchema = <
13870
+ });
13871
+ void (<
13915
13872
  Elements extends
13916
13873
  readonly [typeof String] | readonly [typeof String, typeof Number],
13917
13874
  >(
@@ -13920,35 +13877,16 @@ describe("tuple", () => {
13920
13877
  // @ts-expect-error A union of Tuple schemas is not one concrete schema.
13921
13878
  tuple(...elements);
13922
13879
  return elements;
13923
- };
13880
+ });
13924
13881
 
13925
- const compileTimeAssertions = () => {
13882
+ void (() => {
13926
13883
  // @ts-expect-error A Tuple must contain at least one Type.
13927
13884
  tuple();
13928
13885
  // @ts-expect-error An element must preserve its concrete Type.
13929
13886
  tuple(uncertain);
13930
13887
  // @ts-expect-error A widened array is not a finite Tuple schema.
13931
13888
  tuple(...widened);
13932
- };
13933
-
13934
- assertType<
13935
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
13936
- ? true
13937
- : false,
13938
- true
13939
- >();
13940
- assertType<
13941
- typeof validateUnionElement extends (...args: Array<never>) => unknown
13942
- ? true
13943
- : false,
13944
- true
13945
- >();
13946
- assertType<
13947
- typeof validateTupleSchema extends (...args: Array<never>) => unknown
13948
- ? true
13949
- : false,
13950
- true
13951
- >();
13889
+ });
13952
13890
  });
13953
13891
  });
13954
13892
 
@@ -14811,6 +14749,10 @@ describe("record", () => {
14811
14749
  assertSame(transformed.Values.parent.key, String);
14812
14750
  assertSame(transformed.Values.parent.value, String);
14813
14751
  assertSame(transformed.Values.parent.parent, null);
14752
+ assertType<
14753
+ typeof transformed.Values.parent,
14754
+ RootRecordType<typeof String, typeof String>
14755
+ >();
14814
14756
  assertTrue("parent" in transformed.Values.from);
14815
14757
  assertType<
14816
14758
  "parent" extends keyof typeof transformed.Values.from ? true : false,
@@ -14871,11 +14813,19 @@ describe("record", () => {
14871
14813
  >();
14872
14814
  });
14873
14815
 
14816
+ it("keeps the parent chain finite for widened values", () => {
14817
+ const createLazyRecord = (element: AnyType) =>
14818
+ lazy(() => record(String, element));
14819
+ const Names = createLazyRecord(String);
14820
+
14821
+ assertOk(Names.fromUnknown({ ada: "Lovelace" }), { ada: "Lovelace" });
14822
+ });
14823
+
14874
14824
  it("rejects every key in an empty key domain", () => {
14875
14825
  const Values = record(Never, Number);
14876
14826
  const symbol = globalThis.Symbol();
14877
14827
  const value = { anything: 1 };
14878
- const compileTimeAssertions = () => {
14828
+ void (() => {
14879
14829
  Values.from({});
14880
14830
  Values.to({});
14881
14831
  Values.from({ [symbol]: true });
@@ -14888,16 +14838,10 @@ describe("record", () => {
14888
14838
  Values.orNull(value);
14889
14839
  // @ts-expect-error A Record with Never keys has no properties.
14890
14840
  Values.to(value);
14891
- };
14841
+ });
14892
14842
 
14893
14843
  assertType<typeof Values.Input, Readonly<Record<string, never>>>();
14894
14844
  assertType<typeof Values.Output, Readonly<Record<string, never>>>();
14895
- assertType<
14896
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
14897
- ? true
14898
- : false,
14899
- true
14900
- >();
14901
14845
  assertEqual(Values.fromUnknown({}), ok(createNullRecord({})));
14902
14846
  assertEqual(
14903
14847
  Values.fromUnknown(value),
@@ -14948,7 +14892,7 @@ describe("record", () => {
14948
14892
  type Value = typeof String | typeof Number;
14949
14893
  const key = String as Key;
14950
14894
  const value = String as Value;
14951
- const compileTimeAssertions = () => {
14895
+ void (() => {
14952
14896
  // @ts-expect-error Record key Input and Output must extend string.
14953
14897
  record(Number, String);
14954
14898
  // @ts-expect-error Record key Input and Output must extend string.
@@ -14958,14 +14902,7 @@ describe("record", () => {
14958
14902
  // @ts-expect-error Record value requires one concrete Type node.
14959
14903
  record(String, value);
14960
14904
  record(String, union(String, Number));
14961
- };
14962
-
14963
- assertType<
14964
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
14965
- ? true
14966
- : false,
14967
- true
14968
- >();
14905
+ });
14969
14906
  });
14970
14907
 
14971
14908
  it("distributes key and value errors inside one issue container", () => {
@@ -15400,6 +15337,53 @@ describe("record", () => {
15400
15337
  );
15401
15338
  });
15402
15339
 
15340
+ it("visits Proxy own keys in their listed order", () => {
15341
+ const Values = record(String, Number);
15342
+ const key = globalThis.Symbol("key");
15343
+ const input = new Proxy(
15344
+ { value: "wrong", [key]: 1 },
15345
+ { ownKeys: () => [key, "value"] },
15346
+ );
15347
+
15348
+ assertEqual(
15349
+ Values.fromUnknown(input),
15350
+ err({
15351
+ type: "Record",
15352
+ reason: {
15353
+ kind: "Entries",
15354
+ issues: [
15355
+ {
15356
+ kind: "Key",
15357
+ key,
15358
+ error: { type: "TypeOf", expected: "String", value: key },
15359
+ },
15360
+ ],
15361
+ },
15362
+ }),
15363
+ );
15364
+ assertFalse(Values.is(input));
15365
+ });
15366
+
15367
+ it("rejects a symbol key listed first without reading descriptors", () => {
15368
+ const key = globalThis.Symbol("key");
15369
+ let reads = 0;
15370
+ const input = new Proxy(
15371
+ { value: 1, [key]: 1 },
15372
+ {
15373
+ ownKeys: () => [key, "value"],
15374
+ getOwnPropertyDescriptor: (target, property) => {
15375
+ reads++;
15376
+ return Reflect.getOwnPropertyDescriptor(target, property);
15377
+ },
15378
+ },
15379
+ );
15380
+
15381
+ assertFalse(record(String, Number).is(input));
15382
+ assertEqual(reads, 0);
15383
+ assertFalse(object({}, record(String, Number)).is(input));
15384
+ assertEqual(reads, 0);
15385
+ });
15386
+
15403
15387
  it("collects key and value issues in own-key order", () => {
15404
15388
  const Values = record(literal("allowed"), Number);
15405
15389
  const input = { wrong: "x", allowed: "y" };
@@ -16622,22 +16606,16 @@ describe("object", () => {
16622
16606
  it("exposes readonly properties", () => {
16623
16607
  const props = { value: String, note: optional(Number) };
16624
16608
  const Model = object(props);
16625
- const compileTimeAssertions = () => {
16609
+ void (() => {
16626
16610
  // @ts-expect-error Object properties are readonly.
16627
16611
  Model.props.value = String;
16628
16612
  // @ts-expect-error Optional Object properties are readonly.
16629
16613
  Model.props.note = optional(Number);
16630
16614
  // @ts-expect-error The Type wrapped by an optional property is readonly.
16631
16615
  Model.props.note.type = Number;
16632
- };
16616
+ });
16633
16617
 
16634
16618
  assertType<typeof Model.props, Readonly<typeof props>>();
16635
- assertType<
16636
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
16637
- ? true
16638
- : false,
16639
- true
16640
- >();
16641
16619
  });
16642
16620
 
16643
16621
  it("composes declared properties with a Record", () => {
@@ -16676,16 +16654,14 @@ describe("object", () => {
16676
16654
  const numbersFromStrings = record(String, NumberFromString);
16677
16655
  const recordUnion = Math.random() > 0.5 ? Values : otherRecord;
16678
16656
  const erased: TypeNode = Values;
16679
- const genericRecordAssertion = <
16680
- Rest extends typeof Values | typeof otherRecord,
16681
- >(
16657
+ void (<Rest extends typeof Values | typeof otherRecord>(
16682
16658
  rest: Rest,
16683
16659
  ): Rest => {
16684
16660
  // @ts-expect-error An unresolved generic could be instantiated with a Record Type union.
16685
16661
  object({}, rest);
16686
16662
  return rest;
16687
- };
16688
- const compileTimeAssertions = () => {
16663
+ });
16664
+ void (() => {
16689
16665
  object({ count: Number });
16690
16666
  object({ count: Number }, Values);
16691
16667
  // @ts-expect-error The second argument must be a Record Type.
@@ -16710,18 +16686,12 @@ describe("object", () => {
16710
16686
  Model.from({ count: 0, other: "not a number" });
16711
16687
  // @ts-expect-error Undeclared properties must match the Record value Output.
16712
16688
  Model.to({ count: 0, other: "not a number" });
16713
- };
16689
+ });
16714
16690
  interface Errors {
16715
16691
  readonly count: TypeOfError<"Number">;
16716
16692
  }
16717
16693
 
16718
16694
  assertSame(Model.record, Values);
16719
- assertType<
16720
- typeof genericRecordAssertion extends (...args: Array<never>) => unknown
16721
- ? true
16722
- : false,
16723
- true
16724
- >();
16725
16695
  assertSame(Model.parent, null);
16726
16696
  assertType<
16727
16697
  typeof Model extends ObjectType<
@@ -16761,26 +16731,20 @@ describe("object", () => {
16761
16731
  : false,
16762
16732
  false
16763
16733
  >();
16764
- assertType<
16765
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
16766
- ? true
16767
- : false,
16768
- true
16769
- >();
16770
16734
  });
16771
16735
 
16772
16736
  it("rejects every property in an empty schema", () => {
16773
16737
  const Model = object({});
16774
16738
  const symbol = globalThis.Symbol();
16775
16739
  const value = { anything: 1 };
16776
- const compileTimeAssertions = () => {
16740
+ void (() => {
16777
16741
  Model.from({ [symbol]: true });
16778
16742
  Model.to({ [symbol]: true });
16779
16743
  // @ts-expect-error Object.from requires an object value.
16780
16744
  Model.from(42);
16781
16745
  // @ts-expect-error An empty Object schema has no properties.
16782
16746
  Model.from(value);
16783
- };
16747
+ });
16784
16748
 
16785
16749
  assertType<typeof Model.Input, Readonly<Record<string, never>>>();
16786
16750
  assertType<typeof Model.Output, Readonly<Record<string, never>>>();
@@ -16792,12 +16756,6 @@ describe("object", () => {
16792
16756
  InferErrors<typeof Model>,
16793
16757
  ObjectError<Readonly<Record<never, never>>>
16794
16758
  >();
16795
- assertType<
16796
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
16797
- ? true
16798
- : false,
16799
- true
16800
- >();
16801
16759
  assertEqual(
16802
16760
  Model.fromUnknown(value),
16803
16761
  err({
@@ -16892,9 +16850,7 @@ describe("object", () => {
16892
16850
  const optionalProperty: OptionalProperty<Property> = optional(String);
16893
16851
  const requiredOrOptional = String as
16894
16852
  typeof String | OptionalProperty<typeof String>;
16895
- const genericCompileTimeAssertion = <
16896
- Property extends typeof String | typeof Number,
16897
- >(
16853
+ void (<Property extends typeof String | typeof Number>(
16898
16854
  genericProperty: Property,
16899
16855
  ): Property => {
16900
16856
  // @ts-expect-error An unresolved generic could be instantiated with a property Type union.
@@ -16902,33 +16858,19 @@ describe("object", () => {
16902
16858
  // @ts-expect-error typed preserves Object property validation.
16903
16859
  typed("Generic", { value: genericProperty });
16904
16860
  return genericProperty;
16905
- };
16906
- const compileTimeAssertions = () => {
16861
+ });
16862
+ void (() => {
16907
16863
  // @ts-expect-error A property requires one concrete Type node.
16908
16864
  object({ value: property });
16909
16865
  // @ts-expect-error An optional property requires one concrete Type node.
16910
16866
  optional(property);
16911
- // @ts-expect-error An Object property requires one concrete wrapped Type node.
16912
- object({ value: optionalProperty });
16913
- // @ts-expect-error Requiredness must not depend on a runtime union.
16914
- object({ value: requiredOrOptional });
16915
- };
16916
-
16917
- assertType<Property extends OptionalParameter ? true : false, false>();
16918
- assertType<
16919
- typeof genericCompileTimeAssertion extends (
16920
- ...args: Array<never>
16921
- ) => unknown
16922
- ? true
16923
- : false,
16924
- true
16925
- >();
16926
- assertType<
16927
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
16928
- ? true
16929
- : false,
16930
- true
16931
- >();
16867
+ // @ts-expect-error An Object property requires one concrete wrapped Type node.
16868
+ object({ value: optionalProperty });
16869
+ // @ts-expect-error Requiredness must not depend on a runtime union.
16870
+ object({ value: requiredOrOptional });
16871
+ });
16872
+
16873
+ assertType<Property extends OptionalParameter ? true : false, false>();
16932
16874
  });
16933
16875
 
16934
16876
  it("rejects erased property Types and a union of schemas", () => {
@@ -16940,7 +16882,7 @@ describe("object", () => {
16940
16882
  const getSubsumedProps = (): typeof baseProps | typeof extendedProps =>
16941
16883
  Math.random() > 0.5 ? baseProps : extendedProps;
16942
16884
  const subsumedProps = getSubsumedProps();
16943
- const compileTimeAssertions = () => {
16885
+ void (() => {
16944
16886
  // @ts-expect-error Optional requires a property Type with concrete information.
16945
16887
  optional(type);
16946
16888
  // @ts-expect-error Object requires a property Type with a concrete parent.
@@ -16949,14 +16891,7 @@ describe("object", () => {
16949
16891
  object(props);
16950
16892
  // @ts-expect-error A structurally wider branch is still a schema union.
16951
16893
  object(subsumedProps);
16952
- };
16953
-
16954
- assertType<
16955
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
16956
- ? true
16957
- : false,
16958
- true
16959
- >();
16894
+ });
16960
16895
  });
16961
16896
 
16962
16897
  it("rejects reserved structural error tags in property Types", () => {
@@ -16995,7 +16930,7 @@ describe("object", () => {
16995
16930
  formatTestTypeError,
16996
16931
  );
16997
16932
  const ExcessChild = brand("ExcessChild", Excess);
16998
- const compileTimeAssertions = () => {
16933
+ void (() => {
16999
16934
  // @ts-expect-error ObjectMissingProperty is reserved for Object structure.
17000
16935
  object({ value: Missing });
17001
16936
  // @ts-expect-error Reserved errors are rejected for optional properties too.
@@ -17008,14 +16943,7 @@ describe("object", () => {
17008
16943
  object({ value: optional(Access) });
17009
16944
  // @ts-expect-error ObjectExcessProperty is reserved through child Types and optional properties.
17010
16945
  object({ value: optional(ExcessChild) });
17011
- };
17012
-
17013
- assertType<
17014
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
17015
- ? true
17016
- : false,
17017
- true
17018
- >();
16946
+ });
17019
16947
  });
17020
16948
 
17021
16949
  it("requires a fixed set of string property names", () => {
@@ -17030,7 +16958,7 @@ describe("object", () => {
17030
16958
  const symbol = globalThis.Symbol();
17031
16959
  const number = { 0: String };
17032
16960
  const proto = { ["__proto__"]: String };
17033
- const compileTimeAssertions = () => {
16961
+ void (() => {
17034
16962
  // @ts-expect-error Broad keys belong to a Record Type.
17035
16963
  object(broad);
17036
16964
  // @ts-expect-error Template-pattern keys belong to a Record Type.
@@ -17045,14 +16973,7 @@ describe("object", () => {
17045
16973
  object(number);
17046
16974
  // @ts-expect-error __proto__ is not an Object property name.
17047
16975
  object(proto);
17048
- };
17049
-
17050
- assertType<
17051
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
17052
- ? true
17053
- : false,
17054
- true
17055
- >();
16976
+ });
17056
16977
  });
17057
16978
  });
17058
16979
 
@@ -18086,6 +18007,48 @@ describe("object", () => {
18086
18007
  assertTrue(Model.is({ name: "Ada" }));
18087
18008
  });
18088
18009
 
18010
+ it("compares own keys with the declared keys, not only their count", () => {
18011
+ const Model = object({ name: String, role: String });
18012
+ const reordered = { role: "admin", name: "Ada" };
18013
+ const renamed: unknown = { name: "Ada", title: "admin" };
18014
+
18015
+ const reorderedResult = Model.fromUnknown(reordered);
18016
+ assertOk(reorderedResult);
18017
+ assertSame(reorderedResult.value, reordered);
18018
+ assertTrue(Model.is(reordered));
18019
+
18020
+ const result = Model.fromUnknown(renamed, { errors: "all" });
18021
+ assertEqual(
18022
+ result,
18023
+ err({
18024
+ type: "Object",
18025
+ reason: {
18026
+ kind: "Properties",
18027
+ errors: {
18028
+ role: { type: "ObjectMissingProperty" },
18029
+ title: { type: "ObjectExcessProperty" },
18030
+ },
18031
+ },
18032
+ }),
18033
+ );
18034
+ assertErr(result);
18035
+ assertSame(result.error.reason.kind, "Properties");
18036
+ assertEqual(Reflect.ownKeys(result.error.reason.errors), [
18037
+ "role",
18038
+ "title",
18039
+ ]);
18040
+ assertFalse(Model.is(renamed));
18041
+
18042
+ // Position alone must not skip an undeclared key before declared ones.
18043
+ const prefixed = { title: 1, name: "Ada", role: "admin" };
18044
+ assertFalse(Model.is(prefixed));
18045
+ assertFalse(
18046
+ object({ name: String, role: String }, record(String, String)).is(
18047
+ prefixed,
18048
+ ),
18049
+ );
18050
+ });
18051
+
18089
18052
  it("rejects non-enumerable and symbol excess properties", () => {
18090
18053
  const Model = object({ name: String });
18091
18054
  const symbol = globalThis.Symbol("excess");
@@ -18108,6 +18071,44 @@ describe("object", () => {
18108
18071
  assertEqual(Reflect.ownKeys(errors), ["hidden", symbol]);
18109
18072
  });
18110
18073
 
18074
+ it("visits Proxy own keys in their listed order", () => {
18075
+ const Model = object({ name: String });
18076
+ const symbol = globalThis.Symbol("excess");
18077
+ const value = new Proxy(
18078
+ { name: "Ada", role: "admin", [symbol]: true },
18079
+ { ownKeys: () => [symbol, "role", "name"] },
18080
+ );
18081
+
18082
+ const result = Model.fromUnknown(value);
18083
+ assertErr(result);
18084
+ assertSame(result.error.reason.kind, "Properties");
18085
+ assertEqual(Reflect.ownKeys(result.error.reason.errors), [symbol]);
18086
+ assertFalse(Model.is(value));
18087
+ });
18088
+
18089
+ it("copies earlier unchanged Record properties into a decoded object", () => {
18090
+ const Model = object(
18091
+ { count: Number },
18092
+ record(String, union(Number, setupNumberFromString())),
18093
+ );
18094
+
18095
+ const result = Model.fromUnknown({
18096
+ count: 0,
18097
+ first: 1,
18098
+ second: "2",
18099
+ third: 3,
18100
+ });
18101
+
18102
+ assertOk(result, { count: 0, first: 1, second: 2, third: 3 });
18103
+ assertSame(globalThis.Object.getPrototypeOf(result.value), null);
18104
+ assertEqual(globalThis.Object.keys(result.value), [
18105
+ "count",
18106
+ "first",
18107
+ "second",
18108
+ "third",
18109
+ ]);
18110
+ });
18111
+
18111
18112
  it("rejects exotic declared and Record properties without reading them", () => {
18112
18113
  const Model = object({ count: Number }, record(String, Number));
18113
18114
  let reads = 0;
@@ -18562,6 +18563,43 @@ describe("object", () => {
18562
18563
  });
18563
18564
  });
18564
18565
 
18566
+ it("validates Record property Outputs without decoding them", () => {
18567
+ const Model = object({}, record(String, setupNumberFromString()));
18568
+ const invalid = {
18569
+ first: 1,
18570
+ second: "2",
18571
+ } as unknown as typeof Model.Output;
18572
+
18573
+ assertAssertionError(() => Model.from(invalid), "Expected Object.", {
18574
+ type: "Object",
18575
+ reason: {
18576
+ kind: "Properties",
18577
+ errors: {
18578
+ second: {
18579
+ type: "Record",
18580
+ reason: {
18581
+ kind: "Entries",
18582
+ issues: [
18583
+ {
18584
+ kind: "Value",
18585
+ key: "second",
18586
+ error: {
18587
+ type: "NumberFromString",
18588
+ outputError: {
18589
+ type: "TypeOf",
18590
+ expected: "Number",
18591
+ value: "2",
18592
+ },
18593
+ },
18594
+ },
18595
+ ],
18596
+ },
18597
+ },
18598
+ },
18599
+ },
18600
+ });
18601
+ });
18602
+
18565
18603
  it("validates every property chain from its parent in declaration order", () => {
18566
18604
  const {
18567
18605
  Model,
@@ -18638,10 +18676,10 @@ describe("object", () => {
18638
18676
  const Model = object({ name: String });
18639
18677
  const symbol = globalThis.Symbol();
18640
18678
  const value = { name: "Ada", [symbol]: true };
18641
- const compileTimeAssertions = () => {
18679
+ void (() => {
18642
18680
  Model.from(value);
18643
18681
  Model.to(value);
18644
- };
18682
+ });
18645
18683
 
18646
18684
  assertType<
18647
18685
  typeof Model.Input extends {
@@ -18667,12 +18705,6 @@ describe("object", () => {
18667
18705
  { readonly name: string } extends typeof Model.Output ? true : false,
18668
18706
  true
18669
18707
  >();
18670
- assertType<
18671
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
18672
- ? true
18673
- : false,
18674
- true
18675
- >();
18676
18708
  });
18677
18709
 
18678
18710
  it("return valid Object and Record values", () => {
@@ -18756,7 +18788,7 @@ describe("object", () => {
18756
18788
  name: String,
18757
18789
  };
18758
18790
  const uncertain = String as typeof String | typeof Number;
18759
- const compileTimeAssertions = () => {
18791
+ void (() => {
18760
18792
  // @ts-expect-error Partial Object properties require fixed keys.
18761
18793
  partial(dynamic);
18762
18794
  // @ts-expect-error Nullable Object properties require fixed keys.
@@ -18765,14 +18797,7 @@ describe("object", () => {
18765
18797
  partial({ value: uncertain });
18766
18798
  // @ts-expect-error Nullable Object properties require one concrete Type node.
18767
18799
  nullableToOptional({ value: uncertain });
18768
- };
18769
-
18770
- assertType<
18771
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
18772
- ? true
18773
- : false,
18774
- true
18775
- >();
18800
+ });
18776
18801
  });
18777
18802
 
18778
18803
  describe("omit", () => {
@@ -18796,15 +18821,12 @@ describe("object", () => {
18796
18821
  assertEqual(Empty.props, {});
18797
18822
  assertType<typeof Empty, ObjectType<{}>>();
18798
18823
 
18799
- const compileTimeAssertions = (
18800
- key: "name" | "age",
18801
- keys: ReadonlyArray<"name" | "age">,
18802
- ) => {
18824
+ void ((key: "name" | "age", keys: ReadonlyArray<"name" | "age">) => {
18803
18825
  // @ts-expect-error A runtime key must identify one statically known property.
18804
18826
  omit(User, key);
18805
18827
  // @ts-expect-error A runtime array does not guarantee which properties are omitted.
18806
18828
  omit(User, ...keys);
18807
- };
18829
+ });
18808
18830
 
18809
18831
  const Metadata = object(
18810
18832
  { name: String, age: Number },
@@ -18824,14 +18846,6 @@ describe("object", () => {
18824
18846
  MetadataWithoutAge.fromUnknown({ name: "Ada", age: "unknown" }),
18825
18847
  { name: "Ada", age: "unknown" },
18826
18848
  );
18827
- assertType<
18828
- typeof compileTimeAssertions extends (
18829
- ...args: Array<never>
18830
- ) => unknown
18831
- ? true
18832
- : false,
18833
- true
18834
- >();
18835
18849
  });
18836
18850
 
18837
18851
  it("retains defaulted fields and can remove every default", () => {
@@ -18906,10 +18920,10 @@ describe("result", () => {
18906
18920
  const Pair = tuple(String, Number);
18907
18921
  const PairResult = result(Pair, Pair);
18908
18922
  const NeverResult = result(Never, Never);
18909
- const compileTimeAssertions = () => {
18923
+ void (() => {
18910
18924
  // @ts-expect-error The exact ok discriminator must select the value branch.
18911
18925
  StringResult.from({ ok: false, value: "value" });
18912
- };
18926
+ });
18913
18927
 
18914
18928
  assertEqual(StringResult.name, "DiscriminatedUnion");
18915
18929
  assertEqual(StringResult.key, "ok");
@@ -18929,12 +18943,6 @@ describe("result", () => {
18929
18943
  ]
18930
18944
  >
18931
18945
  >();
18932
- assertType<
18933
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
18934
- ? true
18935
- : false,
18936
- true
18937
- >();
18938
18946
  assertOk(StringResult.fromUnknown({ ok: true, value: "value" }), {
18939
18947
  ok: true,
18940
18948
  value: "value",
@@ -19037,19 +19045,13 @@ describe("typed", () => {
19037
19045
  const Message = discriminatedUnion(Create, Delete);
19038
19046
  type Message = typeof Message.Output;
19039
19047
  type CreateMessage = ExtractTyped<Message, "Create">;
19040
- const compileTimeAssertions = () => {
19048
+ void (() => {
19041
19049
  // @ts-expect-error The selected type must exist in the Output union.
19042
19050
  type Typo = ExtractTyped<Message, "Cretae">;
19043
19051
  assertType<Typo, never>();
19044
- };
19052
+ });
19045
19053
 
19046
19054
  assertType<CreateMessage, typeof Create.Output>();
19047
- assertType<
19048
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
19049
- ? true
19050
- : false,
19051
- true
19052
- >();
19053
19055
  });
19054
19056
 
19055
19057
  it("creates a strict Object with only a literal type property", () => {
@@ -19340,12 +19342,12 @@ describe("typed", () => {
19340
19342
  ValuesWithTag,
19341
19343
  );
19342
19344
  const value = { type: "Open", label: "Label", note: "Note" } as const;
19343
- const compileTimeAssertions = () => {
19345
+ void (() => {
19344
19346
  // @ts-expect-error Additional properties must match the Record value Type.
19345
19347
  Open.from({ type: "Open", label: "Label", score: 1 });
19346
19348
  // @ts-expect-error The declared CanonicalInput must extend the Record value CanonicalInput.
19347
19349
  typed("Open", { fixed: AFromString }, ValuesWithTag);
19348
- };
19350
+ });
19349
19351
 
19350
19352
  assertSame(Open.record, Values);
19351
19353
  assertType<
@@ -19400,12 +19402,6 @@ describe("typed", () => {
19400
19402
  },
19401
19403
  }),
19402
19404
  );
19403
- assertType<
19404
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
19405
- ? true
19406
- : false,
19407
- true
19408
- >();
19409
19405
  });
19410
19406
 
19411
19407
  it("requires one concrete Type name and reserves the type property", () => {
@@ -19423,14 +19419,12 @@ describe("typed", () => {
19423
19419
  const recordUnion = Math.random() > 0.5 ? Values : UnknownValues;
19424
19420
  const erasedRecord: TypeNode = Values;
19425
19421
  const restrictedKeys = record(literal("value"), String);
19426
- const genericTagAssertion = <Tag extends "One" | "Two">(
19427
- tag: Tag,
19428
- ): Tag => {
19422
+ void (<Tag extends "One" | "Two">(tag: Tag): Tag => {
19429
19423
  // @ts-expect-error An unresolved generic could be instantiated with a tag union.
19430
19424
  typed(tag);
19431
19425
  return tag;
19432
- };
19433
- const compileTimeAssertions = () => {
19426
+ });
19427
+ void (() => {
19434
19428
  // @ts-expect-error Type names start with an uppercase letter.
19435
19429
  typed("one");
19436
19430
  // @ts-expect-error A union does not identify one concrete Type name.
@@ -19458,20 +19452,7 @@ describe("typed", () => {
19458
19452
  typed("One", {}, restrictedKeys);
19459
19453
  // @ts-expect-error Declared Inputs and Outputs must extend the Record value Type.
19460
19454
  typed("One", { value: Number }, Values);
19461
- };
19462
-
19463
- assertType<
19464
- typeof genericTagAssertion extends (...args: Array<never>) => unknown
19465
- ? true
19466
- : false,
19467
- true
19468
- >();
19469
- assertType<
19470
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
19471
- ? true
19472
- : false,
19473
- true
19474
- >();
19455
+ });
19475
19456
  });
19476
19457
  });
19477
19458
 
@@ -19479,10 +19460,10 @@ describe("typed", () => {
19479
19460
  it("rejects missing, mismatched, and excess properties", () => {
19480
19461
  const Empty = typed("Empty");
19481
19462
  const valueWithExcessProperty = { type: "Empty", extra: true } as const;
19482
- const compileTimeAssertions = () => {
19463
+ void (() => {
19483
19464
  // @ts-expect-error Strict typed Input excludes excess properties.
19484
19465
  Empty.from({ type: "Empty", extra: true });
19485
- };
19466
+ });
19486
19467
 
19487
19468
  assertEqual(
19488
19469
  Empty.fromUnknown({}),
@@ -19506,12 +19487,6 @@ describe("typed", () => {
19506
19487
  }),
19507
19488
  );
19508
19489
  assertFalse(Empty.is(valueWithExcessProperty));
19509
- assertType<
19510
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
19511
- ? true
19512
- : false,
19513
- true
19514
- >();
19515
19490
  });
19516
19491
  });
19517
19492
 
@@ -19771,7 +19746,7 @@ describe("discriminatedUnion", () => {
19771
19746
  const broadKey = "type" as string;
19772
19747
  const unionKey = "type" as "type" | "kind";
19773
19748
  const patternedKey = "type" as `type${string}`;
19774
- const compileTimeAssertions = () => {
19749
+ void (() => {
19775
19750
  // @ts-expect-error A Discriminated Union requires at least two members.
19776
19751
  discriminatedUnion();
19777
19752
  // @ts-expect-error A Discriminated Union requires at least two members.
@@ -19798,14 +19773,7 @@ describe("discriminatedUnion", () => {
19798
19773
  discriminatedUnion(unionKey, Valid, typed("Other"));
19799
19774
  // @ts-expect-error The explicit discriminator key must not be a template pattern.
19800
19775
  discriminatedUnion(patternedKey, Valid, typed("Other"));
19801
- };
19802
-
19803
- assertType<
19804
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
19805
- ? true
19806
- : false,
19807
- true
19808
- >();
19776
+ });
19809
19777
  });
19810
19778
 
19811
19779
  it("requires one concrete finite member tuple", () => {
@@ -19830,7 +19798,7 @@ describe("discriminatedUnion", () => {
19830
19798
  ] = [OneWithString, TwoWithString];
19831
19799
  const uncertainThird = ThreeWithString as
19832
19800
  typeof ThreeWithString | typeof _ThreeWithNumber;
19833
- const compileTimeAssertions = () => {
19801
+ void (() => {
19834
19802
  // @ts-expect-error Members must use one concrete finite tuple.
19835
19803
  discriminatedUnion(...members);
19836
19804
  // @ts-expect-error Explicit-key members must also use one concrete finite tuple.
@@ -19841,14 +19809,7 @@ describe("discriminatedUnion", () => {
19841
19809
  discriminatedUnion(...widenedMembers);
19842
19810
  // @ts-expect-error Every member slot must use one concrete Object Type.
19843
19811
  discriminatedUnion(OneWithString, TwoWithString, uncertainThird);
19844
- };
19845
-
19846
- assertType<
19847
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
19848
- ? true
19849
- : false,
19850
- true
19851
- >();
19812
+ });
19852
19813
  });
19853
19814
  });
19854
19815
 
@@ -19987,10 +19948,10 @@ describe("discriminatedUnion", () => {
19987
19948
  const Deleted = typed("Deleted", { reason: String });
19988
19949
  const Event = discriminatedUnion(Created, Deleted);
19989
19950
  const uncorrelated = { type: "Created", reason: "reason" } as const;
19990
- const compileTimeAssertions = () => {
19951
+ void (() => {
19991
19952
  // @ts-expect-error The exact discriminator must correlate with its member Input.
19992
19953
  Event.from(uncorrelated);
19993
- };
19954
+ });
19994
19955
 
19995
19956
  assertType<
19996
19957
  typeof uncorrelated extends typeof Event.Input ? true : false,
@@ -20016,12 +19977,6 @@ describe("discriminatedUnion", () => {
20016
19977
  },
20017
19978
  }),
20018
19979
  );
20019
- assertType<
20020
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
20021
- ? true
20022
- : false,
20023
- true
20024
- >();
20025
19980
  });
20026
19981
 
20027
19982
  it("returns routed discriminator, access, and member errors", () => {
@@ -20397,43 +20352,28 @@ describe("lazy", () => {
20397
20352
  type Definition = Parameters<typeof lazy<Target>>[0];
20398
20353
  type DefinitionOutput = ReturnType<Definition>;
20399
20354
  const getTarget = (): Target => chooseTarget(true);
20400
- const compileTimeAssertions = () => {
20355
+ void (() => {
20401
20356
  // @ts-expect-error A Lazy Type definition must return one concrete Type node.
20402
20357
  lazy(getTarget);
20403
20358
  // @ts-expect-error An inferred Lazy Type definition must also return one concrete Type node.
20404
20359
  lazy(() => chooseTarget(true));
20405
- };
20360
+ });
20406
20361
 
20407
20362
  assertType<Target extends DefinitionOutput ? true : false, false>();
20408
20363
  assertType<
20409
20364
  DefinitionOutput,
20410
20365
  "⛔ Type error: Lazy Type definition must return one concrete Type node. Pass a Union Type node instead of a union of Type nodes."
20411
20366
  >();
20412
- assertType<
20413
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
20414
- ? true
20415
- : false,
20416
- true
20417
- >();
20418
20367
  });
20419
20368
 
20420
20369
  it("rejects an unresolved generic definition", () => {
20421
- const compileTimeAssertions = <
20422
- Target extends typeof String | typeof Number,
20423
- >(
20370
+ void (<Target extends typeof String | typeof Number>(
20424
20371
  target: Target,
20425
20372
  ): Target => {
20426
20373
  // @ts-expect-error An unresolved generic target might be a union.
20427
20374
  lazy(() => target);
20428
20375
  return target;
20429
- };
20430
-
20431
- assertType<
20432
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
20433
- ? true
20434
- : false,
20435
- true
20436
- >();
20376
+ });
20437
20377
  });
20438
20378
 
20439
20379
  it("accepts one Union Type node as its definition", () => {
@@ -21310,6 +21250,20 @@ describe("Data", () => {
21310
21250
  );
21311
21251
  assertFalse(Data.fromUnknown(sparse, { errors: "all" }).ok);
21312
21252
 
21253
+ // The index after a hole is listed at an earlier position.
21254
+ const trailing = createMutableArray<Data>(2);
21255
+ trailing[1] = 1;
21256
+ assertEqual(
21257
+ Data.fromUnknown(trailing, { errors: "all" }),
21258
+ err({
21259
+ type: "Data",
21260
+ reason: {
21261
+ kind: "Issues",
21262
+ issues: [{ kind: "Hole", path: [0] }],
21263
+ },
21264
+ }),
21265
+ );
21266
+
21313
21267
  let reads = 0;
21314
21268
  const accessor = createMutableArray<Data>(1);
21315
21269
  globalThis.Object.defineProperty(accessor, 0, {
@@ -22136,7 +22090,7 @@ describe("json", () => {
22136
22090
  >();
22137
22091
  assertType<ReturnType<typeof Person.to>, typeof Person.CanonicalInput>();
22138
22092
 
22139
- const compileTimeAssertions = () => {
22093
+ void (() => {
22140
22094
  type InvalidCanonicalInput = Type<
22141
22095
  "InvalidCanonicalInput",
22142
22096
  string,
@@ -22154,14 +22108,7 @@ describe("json", () => {
22154
22108
  // The encoder's actual image is finite, but CanonicalInput is number.
22155
22109
  // @ts-expect-error Type CanonicalInput must be JSON-compatible.
22156
22110
  json(_FiniteAfterNumberTransform, "FiniteAfterNumberTransformJson");
22157
- };
22158
-
22159
- assertType<
22160
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
22161
- ? true
22162
- : false,
22163
- true
22164
- >();
22111
+ });
22165
22112
  });
22166
22113
 
22167
22114
  it("creates a branded Json Type and total typed conversions", () => {
@@ -22405,7 +22352,7 @@ describe("json", () => {
22405
22352
  });
22406
22353
 
22407
22354
  it("accepts only Types with a JSON-compatible canonical Input", () => {
22408
- const compileTimeAssertions = () => {
22355
+ void (() => {
22409
22356
  interface StringTree {
22410
22357
  readonly value: string;
22411
22358
  readonly children: ReadonlyArray<StringTree>;
@@ -22762,14 +22709,7 @@ describe("json", () => {
22762
22709
 
22763
22710
  // @ts-expect-error Type CanonicalInput must be JSON-compatible.
22764
22711
  json(NonCanonicalArrayIndex, "NonCanonicalArrayIndexJson");
22765
- };
22766
-
22767
- assertType<
22768
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
22769
- ? true
22770
- : false,
22771
- true
22772
- >();
22712
+ });
22773
22713
  });
22774
22714
 
22775
22715
  it("forwards ValidationOptions to the represented Type", () => {
@@ -22911,7 +22851,7 @@ describe("json", () => {
22911
22851
  describe("design decisions", () => {
22912
22852
  describe("typed inputs", () => {
22913
22853
  it("protect append-only fields from incompatible component changes", () => {
22914
- const compileTimeAssertions = () => {
22854
+ void (() => {
22915
22855
  const Todo = object({ title: NonEmptyTrimmedString100 });
22916
22856
 
22917
22857
  // The input guarantees the same constraints as the domain model.
@@ -22939,18 +22879,11 @@ describe("design decisions", () => {
22939
22879
  };
22940
22880
 
22941
22881
  return { inputOnChange, longerInputOnChange };
22942
- };
22943
-
22944
- assertType<
22945
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
22946
- ? true
22947
- : false,
22948
- true
22949
- >();
22882
+ });
22950
22883
  });
22951
22884
 
22952
22885
  it("compose one weaker component output", () => {
22953
- const compileTimeAssertions = () => {
22886
+ void (() => {
22954
22887
  const Todo = object({
22955
22888
  title: NonEmptyTrimmedString100,
22956
22889
  note: NonEmptyTrimmedString100,
@@ -22980,18 +22913,11 @@ describe("design decisions", () => {
22980
22913
  };
22981
22914
 
22982
22915
  return saveTodo;
22983
- };
22984
-
22985
- assertType<
22986
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
22987
- ? true
22988
- : false,
22989
- true
22990
- >();
22916
+ });
22991
22917
  });
22992
22918
 
22993
22919
  it("compose trim-only component outputs", () => {
22994
- const compileTimeAssertions = () => {
22920
+ void (() => {
22995
22921
  const Todo = object({
22996
22922
  title: NonEmptyTrimmedString100,
22997
22923
  note: NonEmptyTrimmedString100,
@@ -23013,14 +22939,7 @@ describe("design decisions", () => {
23013
22939
  >();
23014
22940
 
23015
22941
  return saveTodo;
23016
- };
23017
-
23018
- assertType<
23019
- typeof compileTimeAssertions extends (...args: Array<never>) => unknown
23020
- ? true
23021
- : false,
23022
- true
23023
- >();
22942
+ });
23024
22943
  });
23025
22944
  });
23026
22945
 
@@ -23380,7 +23299,7 @@ describe("objectKeys", () => {
23380
23299
  });
23381
23300
 
23382
23301
  it("requires string key codecs and a concrete strict object", () => {
23383
- const reject = () => {
23302
+ void (() => {
23384
23303
  // @ts-expect-error Key Output must be string.
23385
23304
  objectKeys(PortFromString);
23386
23305
  // @ts-expect-error objectKeys requires a strict Object Type without a record rest.
@@ -23392,8 +23311,7 @@ describe("objectKeys", () => {
23392
23311
  : object({ age: Number });
23393
23312
  // @ts-expect-error Output Type must be one concrete Type node. Pass a Union Type node instead of a union of Type nodes.
23394
23313
  objectKeys(String)(objectType);
23395
- };
23396
- assertType<typeof reject, () => void>();
23314
+ });
23397
23315
  });
23398
23316
  });
23399
23317