@evolu/common 8.5.0 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/dist/src/Array.d.ts +170 -97
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +67 -42
  4. package/dist/src/Assert.d.ts +233 -30
  5. package/dist/src/Assert.d.ts.map +1 -1
  6. package/dist/src/Assert.js +150 -30
  7. package/dist/src/BigInt.d.ts +3 -3
  8. package/dist/src/BigInt.js +3 -3
  9. package/dist/src/Brand.d.ts +7 -7
  10. package/dist/src/Buffer.d.ts +12 -4
  11. package/dist/src/Buffer.d.ts.map +1 -1
  12. package/dist/src/Cache.d.ts +8 -3
  13. package/dist/src/Cache.d.ts.map +1 -1
  14. package/dist/src/Cache.js +8 -3
  15. package/dist/src/Callbacks.d.ts +8 -4
  16. package/dist/src/Callbacks.d.ts.map +1 -1
  17. package/dist/src/Console.d.ts +45 -30
  18. package/dist/src/Console.d.ts.map +1 -1
  19. package/dist/src/Console.js +32 -21
  20. package/dist/src/Crypto.d.ts +13 -8
  21. package/dist/src/Crypto.d.ts.map +1 -1
  22. package/dist/src/Crypto.js +6 -3
  23. package/dist/src/Eq.d.ts +107 -58
  24. package/dist/src/Eq.d.ts.map +1 -1
  25. package/dist/src/Eq.js +308 -112
  26. package/dist/src/Function.d.ts +54 -24
  27. package/dist/src/Function.d.ts.map +1 -1
  28. package/dist/src/Function.js +34 -17
  29. package/dist/src/Http.d.ts +52 -19
  30. package/dist/src/Http.d.ts.map +1 -1
  31. package/dist/src/Identicon.d.ts +9 -4
  32. package/dist/src/Identicon.d.ts.map +1 -1
  33. package/dist/src/Identicon.js +9 -4
  34. package/dist/src/LockManager.d.ts +12 -10
  35. package/dist/src/LockManager.d.ts.map +1 -1
  36. package/dist/src/Lookup.d.ts +4 -2
  37. package/dist/src/Lookup.d.ts.map +1 -1
  38. package/dist/src/Lookup.js +4 -2
  39. package/dist/src/Number.d.ts +28 -24
  40. package/dist/src/Number.d.ts.map +1 -1
  41. package/dist/src/Number.js +16 -17
  42. package/dist/src/Object.d.ts +89 -47
  43. package/dist/src/Object.d.ts.map +1 -1
  44. package/dist/src/Object.js +88 -41
  45. package/dist/src/Option.d.ts +14 -5
  46. package/dist/src/Option.d.ts.map +1 -1
  47. package/dist/src/Option.js +14 -5
  48. package/dist/src/Order.d.ts +12 -12
  49. package/dist/src/Order.js +12 -12
  50. package/dist/src/Platform.d.ts +2 -2
  51. package/dist/src/Random.d.ts +7 -4
  52. package/dist/src/Random.d.ts.map +1 -1
  53. package/dist/src/Redacted.d.ts +13 -6
  54. package/dist/src/Redacted.d.ts.map +1 -1
  55. package/dist/src/Redacted.js +4 -2
  56. package/dist/src/Ref.d.ts +4 -4
  57. package/dist/src/Relation.d.ts +5 -7
  58. package/dist/src/Relation.d.ts.map +1 -1
  59. package/dist/src/Resource.d.ts +27 -12
  60. package/dist/src/Resource.d.ts.map +1 -1
  61. package/dist/src/Result.d.ts +258 -114
  62. package/dist/src/Result.d.ts.map +1 -1
  63. package/dist/src/Result.js +71 -34
  64. package/dist/src/Schedule.d.ts +233 -116
  65. package/dist/src/Schedule.d.ts.map +1 -1
  66. package/dist/src/Schedule.js +204 -110
  67. package/dist/src/Set.d.ts +43 -24
  68. package/dist/src/Set.d.ts.map +1 -1
  69. package/dist/src/Set.js +25 -13
  70. package/dist/src/Sqlite.d.ts +4 -4
  71. package/dist/src/Sqlite.d.ts.map +1 -1
  72. package/dist/src/Sqlite.js +9 -8
  73. package/dist/src/Task.d.ts +441 -212
  74. package/dist/src/Task.d.ts.map +1 -1
  75. package/dist/src/Task.js +238 -115
  76. package/dist/src/Test.d.ts +10 -4
  77. package/dist/src/Test.d.ts.map +1 -1
  78. package/dist/src/Test.js +10 -4
  79. package/dist/src/Time.d.ts +27 -17
  80. package/dist/src/Time.d.ts.map +1 -1
  81. package/dist/src/Time.js +16 -6
  82. package/dist/src/Type.d.ts +1096 -387
  83. package/dist/src/Type.d.ts.map +1 -1
  84. package/dist/src/Type.js +1046 -372
  85. package/dist/src/Types.d.ts +95 -40
  86. package/dist/src/Types.d.ts.map +1 -1
  87. package/dist/src/Types.js +13 -4
  88. package/dist/src/WebSocket.d.ts +14 -6
  89. package/dist/src/WebSocket.d.ts.map +1 -1
  90. package/dist/src/Worker.d.ts +10 -6
  91. package/dist/src/Worker.d.ts.map +1 -1
  92. package/dist/src/intl/_en.d.ts +3 -1
  93. package/dist/src/intl/_en.d.ts.map +1 -1
  94. package/dist/src/intl/_en.js +17 -3
  95. package/dist/src/intl/ar.d.ts +3 -1
  96. package/dist/src/intl/ar.d.ts.map +1 -1
  97. package/dist/src/intl/ar.js +15 -2
  98. package/dist/src/intl/bn.d.ts +3 -1
  99. package/dist/src/intl/bn.d.ts.map +1 -1
  100. package/dist/src/intl/bn.js +16 -3
  101. package/dist/src/intl/ca.d.ts +3 -1
  102. package/dist/src/intl/ca.d.ts.map +1 -1
  103. package/dist/src/intl/ca.js +16 -3
  104. package/dist/src/intl/cs.d.ts +3 -1
  105. package/dist/src/intl/cs.d.ts.map +1 -1
  106. package/dist/src/intl/cs.js +16 -3
  107. package/dist/src/intl/da.d.ts +3 -1
  108. package/dist/src/intl/da.d.ts.map +1 -1
  109. package/dist/src/intl/da.js +16 -3
  110. package/dist/src/intl/de.d.ts +3 -1
  111. package/dist/src/intl/de.d.ts.map +1 -1
  112. package/dist/src/intl/de.js +16 -3
  113. package/dist/src/intl/el.d.ts +3 -1
  114. package/dist/src/intl/el.d.ts.map +1 -1
  115. package/dist/src/intl/el.js +16 -3
  116. package/dist/src/intl/es.d.ts +3 -1
  117. package/dist/src/intl/es.d.ts.map +1 -1
  118. package/dist/src/intl/es.js +16 -3
  119. package/dist/src/intl/fa.d.ts +3 -1
  120. package/dist/src/intl/fa.d.ts.map +1 -1
  121. package/dist/src/intl/fa.js +16 -3
  122. package/dist/src/intl/fi.d.ts +3 -1
  123. package/dist/src/intl/fi.d.ts.map +1 -1
  124. package/dist/src/intl/fi.js +16 -3
  125. package/dist/src/intl/fil.d.ts +3 -1
  126. package/dist/src/intl/fil.d.ts.map +1 -1
  127. package/dist/src/intl/fil.js +16 -3
  128. package/dist/src/intl/fr.d.ts +3 -1
  129. package/dist/src/intl/fr.d.ts.map +1 -1
  130. package/dist/src/intl/fr.js +16 -3
  131. package/dist/src/intl/he.d.ts +3 -1
  132. package/dist/src/intl/he.d.ts.map +1 -1
  133. package/dist/src/intl/he.js +16 -3
  134. package/dist/src/intl/hi.d.ts +3 -1
  135. package/dist/src/intl/hi.d.ts.map +1 -1
  136. package/dist/src/intl/hi.js +16 -3
  137. package/dist/src/intl/hr.d.ts +3 -1
  138. package/dist/src/intl/hr.d.ts.map +1 -1
  139. package/dist/src/intl/hr.js +16 -3
  140. package/dist/src/intl/hu.d.ts +2 -1
  141. package/dist/src/intl/hu.d.ts.map +1 -1
  142. package/dist/src/intl/hu.js +15 -3
  143. package/dist/src/intl/id.d.ts +3 -1
  144. package/dist/src/intl/id.d.ts.map +1 -1
  145. package/dist/src/intl/id.js +16 -3
  146. package/dist/src/intl/it.d.ts +3 -1
  147. package/dist/src/intl/it.d.ts.map +1 -1
  148. package/dist/src/intl/it.js +16 -3
  149. package/dist/src/intl/ja.d.ts +3 -1
  150. package/dist/src/intl/ja.d.ts.map +1 -1
  151. package/dist/src/intl/ja.js +16 -3
  152. package/dist/src/intl/ko.d.ts +3 -1
  153. package/dist/src/intl/ko.d.ts.map +1 -1
  154. package/dist/src/intl/ko.js +16 -3
  155. package/dist/src/intl/ml.d.ts +3 -1
  156. package/dist/src/intl/ml.d.ts.map +1 -1
  157. package/dist/src/intl/ml.js +16 -3
  158. package/dist/src/intl/mr.d.ts +3 -1
  159. package/dist/src/intl/mr.d.ts.map +1 -1
  160. package/dist/src/intl/mr.js +16 -3
  161. package/dist/src/intl/ms.d.ts +3 -1
  162. package/dist/src/intl/ms.d.ts.map +1 -1
  163. package/dist/src/intl/ms.js +15 -2
  164. package/dist/src/intl/nb.d.ts +2 -1
  165. package/dist/src/intl/nb.d.ts.map +1 -1
  166. package/dist/src/intl/nb.js +14 -2
  167. package/dist/src/intl/nl.d.ts +3 -1
  168. package/dist/src/intl/nl.d.ts.map +1 -1
  169. package/dist/src/intl/nl.js +16 -3
  170. package/dist/src/intl/pa.d.ts +3 -1
  171. package/dist/src/intl/pa.d.ts.map +1 -1
  172. package/dist/src/intl/pa.js +16 -3
  173. package/dist/src/intl/pl.d.ts +2 -0
  174. package/dist/src/intl/pl.d.ts.map +1 -1
  175. package/dist/src/intl/pl.js +15 -2
  176. package/dist/src/intl/pt-BR.d.ts +3 -1
  177. package/dist/src/intl/pt-BR.d.ts.map +1 -1
  178. package/dist/src/intl/pt-BR.js +16 -3
  179. package/dist/src/intl/pt.d.ts +3 -1
  180. package/dist/src/intl/pt.d.ts.map +1 -1
  181. package/dist/src/intl/pt.js +15 -2
  182. package/dist/src/intl/ro.d.ts +3 -1
  183. package/dist/src/intl/ro.d.ts.map +1 -1
  184. package/dist/src/intl/ro.js +16 -3
  185. package/dist/src/intl/sk.d.ts +3 -1
  186. package/dist/src/intl/sk.d.ts.map +1 -1
  187. package/dist/src/intl/sk.js +15 -2
  188. package/dist/src/intl/sl.d.ts +3 -1
  189. package/dist/src/intl/sl.d.ts.map +1 -1
  190. package/dist/src/intl/sl.js +16 -3
  191. package/dist/src/intl/sv.d.ts +3 -1
  192. package/dist/src/intl/sv.d.ts.map +1 -1
  193. package/dist/src/intl/sv.js +16 -3
  194. package/dist/src/intl/sw.d.ts +1 -0
  195. package/dist/src/intl/sw.d.ts.map +1 -1
  196. package/dist/src/intl/sw.js +14 -2
  197. package/dist/src/intl/ta.d.ts +3 -1
  198. package/dist/src/intl/ta.d.ts.map +1 -1
  199. package/dist/src/intl/ta.js +16 -3
  200. package/dist/src/intl/te.d.ts +3 -1
  201. package/dist/src/intl/te.d.ts.map +1 -1
  202. package/dist/src/intl/te.js +16 -3
  203. package/dist/src/intl/th.d.ts +3 -1
  204. package/dist/src/intl/th.d.ts.map +1 -1
  205. package/dist/src/intl/th.js +16 -3
  206. package/dist/src/intl/tr.d.ts +3 -1
  207. package/dist/src/intl/tr.d.ts.map +1 -1
  208. package/dist/src/intl/tr.js +16 -3
  209. package/dist/src/intl/uk.d.ts +3 -1
  210. package/dist/src/intl/uk.d.ts.map +1 -1
  211. package/dist/src/intl/uk.js +16 -3
  212. package/dist/src/intl/ur.d.ts +3 -1
  213. package/dist/src/intl/ur.d.ts.map +1 -1
  214. package/dist/src/intl/ur.js +15 -2
  215. package/dist/src/intl/vi.d.ts +3 -1
  216. package/dist/src/intl/vi.d.ts.map +1 -1
  217. package/dist/src/intl/vi.js +16 -3
  218. package/dist/src/intl/zh-CN.d.ts +3 -1
  219. package/dist/src/intl/zh-CN.d.ts.map +1 -1
  220. package/dist/src/intl/zh-CN.js +16 -3
  221. package/dist/src/intl/zh-TW.d.ts +3 -1
  222. package/dist/src/intl/zh-TW.d.ts.map +1 -1
  223. package/dist/src/intl/zh-TW.js +16 -3
  224. package/dist/src/local-first/Evolu.d.ts +47 -24
  225. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  226. package/dist/src/local-first/Owner.d.ts +10 -7
  227. package/dist/src/local-first/Owner.d.ts.map +1 -1
  228. package/dist/src/local-first/Owner.js +10 -7
  229. package/dist/src/local-first/Protocol.d.ts +5 -5
  230. package/dist/src/local-first/Protocol.js +5 -5
  231. package/dist/src/local-first/Query.d.ts +34 -21
  232. package/dist/src/local-first/Query.d.ts.map +1 -1
  233. package/dist/src/local-first/Query.js +25 -13
  234. package/dist/src/local-first/Relay.d.ts +12 -5
  235. package/dist/src/local-first/Relay.d.ts.map +1 -1
  236. package/dist/src/local-first/Schema.d.ts +19 -11
  237. package/dist/src/local-first/Schema.d.ts.map +1 -1
  238. package/dist/src/local-first/Schema.js +11 -6
  239. package/dist/src/local-first/Storage.d.ts +4 -2
  240. package/dist/src/local-first/Storage.d.ts.map +1 -1
  241. package/package.json +3 -4
  242. package/src/Array.ts +170 -97
  243. package/src/Assert.ts +336 -31
  244. package/src/BigInt.ts +3 -3
  245. package/src/Brand.ts +7 -7
  246. package/src/Buffer.ts +12 -4
  247. package/src/Cache.ts +8 -3
  248. package/src/Callbacks.ts +8 -4
  249. package/src/Console.ts +45 -30
  250. package/src/Crypto.ts +13 -8
  251. package/src/Eq.ts +450 -122
  252. package/src/Function.ts +54 -24
  253. package/src/Http.ts +52 -19
  254. package/src/Identicon.ts +9 -4
  255. package/src/LockManager.ts +12 -10
  256. package/src/Lookup.ts +4 -2
  257. package/src/Number.ts +28 -24
  258. package/src/Object.ts +115 -49
  259. package/src/Option.ts +14 -5
  260. package/src/Order.ts +12 -12
  261. package/src/Platform.ts +2 -2
  262. package/src/Random.ts +7 -4
  263. package/src/Redacted.ts +13 -6
  264. package/src/Ref.ts +4 -4
  265. package/src/Relation.ts +5 -7
  266. package/src/Resource.ts +27 -12
  267. package/src/Result.ts +258 -114
  268. package/src/Schedule.ts +233 -116
  269. package/src/Set.ts +43 -24
  270. package/src/Sqlite.ts +9 -8
  271. package/src/Task.ts +441 -212
  272. package/src/Test.ts +10 -4
  273. package/src/Time.ts +27 -17
  274. package/src/Type.ts +2077 -620
  275. package/src/Types.ts +108 -40
  276. package/src/WebSocket.ts +14 -6
  277. package/src/Worker.ts +10 -6
  278. package/src/intl/_en.ts +20 -4
  279. package/src/intl/ar.ts +17 -2
  280. package/src/intl/bn.ts +19 -4
  281. package/src/intl/ca.ts +19 -4
  282. package/src/intl/cs.ts +19 -4
  283. package/src/intl/da.ts +19 -4
  284. package/src/intl/de.ts +19 -4
  285. package/src/intl/el.ts +19 -4
  286. package/src/intl/es.ts +19 -4
  287. package/src/intl/fa.ts +19 -4
  288. package/src/intl/fi.ts +19 -4
  289. package/src/intl/fil.ts +19 -4
  290. package/src/intl/fr.ts +19 -4
  291. package/src/intl/he.ts +19 -4
  292. package/src/intl/hi.ts +19 -4
  293. package/src/intl/hr.ts +19 -4
  294. package/src/intl/hu.ts +18 -4
  295. package/src/intl/id.ts +19 -4
  296. package/src/intl/it.ts +19 -4
  297. package/src/intl/ja.ts +19 -4
  298. package/src/intl/ko.ts +19 -4
  299. package/src/intl/ml.ts +19 -4
  300. package/src/intl/mr.ts +19 -4
  301. package/src/intl/ms.ts +17 -2
  302. package/src/intl/nb.ts +16 -2
  303. package/src/intl/nl.ts +19 -4
  304. package/src/intl/pa.ts +19 -4
  305. package/src/intl/pl.ts +18 -2
  306. package/src/intl/pt-BR.ts +19 -4
  307. package/src/intl/pt.ts +17 -2
  308. package/src/intl/ro.ts +19 -4
  309. package/src/intl/sk.ts +17 -2
  310. package/src/intl/sl.ts +19 -4
  311. package/src/intl/sv.ts +19 -4
  312. package/src/intl/sw.ts +15 -2
  313. package/src/intl/ta.ts +19 -4
  314. package/src/intl/te.ts +19 -4
  315. package/src/intl/th.ts +19 -4
  316. package/src/intl/tr.ts +19 -4
  317. package/src/intl/uk.ts +19 -4
  318. package/src/intl/ur.ts +17 -2
  319. package/src/intl/vi.ts +19 -3
  320. package/src/intl/zh-CN.ts +19 -4
  321. package/src/intl/zh-TW.ts +19 -4
  322. package/src/local-first/Evolu.ts +47 -24
  323. package/src/local-first/Owner.ts +10 -7
  324. package/src/local-first/Protocol.ts +5 -5
  325. package/src/local-first/Query.ts +34 -21
  326. package/src/local-first/Relay.ts +12 -5
  327. package/src/local-first/Schema.ts +19 -11
  328. package/src/local-first/Storage.ts +4 -2
package/src/Types.ts CHANGED
@@ -12,7 +12,12 @@
12
12
  * ### Completion callbacks
13
13
  *
14
14
  * ```ts
15
- * import { ok, type Callback, type Result } from "@evolu/common";
15
+ * import {
16
+ * assertEqual,
17
+ * ok,
18
+ * type Callback,
19
+ * type Result,
20
+ * } from "@evolu/common";
16
21
  *
17
22
  * const completedValues: Array<string> = [];
18
23
  * const onComplete: Callback<string> = (value) => {
@@ -26,7 +31,7 @@
26
31
  * onComplete("direct");
27
32
  * for (const callback of queue) callback(ok("queued"));
28
33
  *
29
- * expect(completedValues).toEqual(["direct", "queued"]);
34
+ * assertEqual(completedValues, ["direct", "queued"]);
30
35
  * ```
31
36
  */
32
37
  export type Callback<T> = (value: T) => void;
@@ -39,7 +44,7 @@ export type Callback<T> = (value: T) => void;
39
44
  * ### Subscription teardown
40
45
  *
41
46
  * ```ts
42
- * import type { CallbackWithTeardown } from "@evolu/common";
47
+ * import { assertEqual, type CallbackWithTeardown } from "@evolu/common";
43
48
  *
44
49
  * interface EventSource {
45
50
  * readonly start: () => void;
@@ -48,8 +53,12 @@ export type Callback<T> = (value: T) => void;
48
53
  *
49
54
  * const events: Array<string> = [];
50
55
  * const source: EventSource = {
51
- * start: () => events.push("started"),
52
- * stop: () => events.push("stopped"),
56
+ * start: () => {
57
+ * events.push("started");
58
+ * },
59
+ * stop: () => {
60
+ * events.push("stopped");
61
+ * },
53
62
  * };
54
63
  * const subscribe: CallbackWithTeardown<EventSource> = (source) => {
55
64
  * source.start();
@@ -58,7 +67,7 @@ export type Callback<T> = (value: T) => void;
58
67
  * const teardown = subscribe(source);
59
68
  * if (teardown) teardown();
60
69
  *
61
- * expect(events).toEqual(["started", "stopped"]);
70
+ * assertEqual(events, ["started", "stopped"]);
62
71
  * ```
63
72
  */
64
73
  export type CallbackWithTeardown<T> = (value: T) => void | (() => void);
@@ -71,11 +80,11 @@ export type CallbackWithTeardown<T> = (value: T) => void | (() => void);
71
80
  * ### Filtering values
72
81
  *
73
82
  * ```ts
74
- * import type { Predicate } from "@evolu/common";
83
+ * import { assertEqual, type Predicate } from "@evolu/common";
75
84
  *
76
85
  * const isEven: Predicate<number> = (n) => n % 2 === 0;
77
86
  *
78
- * expect([1, 2, 3, 4].filter(isEven)).toEqual([2, 4]);
87
+ * assertEqual([1, 2, 3, 4].filter(isEven), [2, 4]);
79
88
  * ```
80
89
  */
81
90
  export type Predicate<T> = (value: T) => boolean;
@@ -88,12 +97,12 @@ export type Predicate<T> = (value: T) => boolean;
88
97
  * ### Filtering by position
89
98
  *
90
99
  * ```ts
91
- * import type { PredicateWithIndex } from "@evolu/common";
100
+ * import { assertEqual, type PredicateWithIndex } from "@evolu/common";
92
101
  *
93
- * const isEvenIndex: PredicateWithIndex<string> = (value, index) =>
102
+ * const isEvenIndex: PredicateWithIndex<string> = (_value, index) =>
94
103
  * index % 2 === 0;
95
104
  *
96
- * expect(["a", "b", "c", "d"].filter(isEvenIndex)).toEqual(["a", "c"]);
105
+ * assertEqual(["a", "b", "c", "d"].filter(isEvenIndex), ["a", "c"]);
97
106
  * ```
98
107
  */
99
108
  export type PredicateWithIndex<T> = (value: T, index: number) => boolean;
@@ -104,7 +113,7 @@ export type PredicateWithIndex<T> = (value: T, index: number) => boolean;
104
113
  * ### Narrowing a value
105
114
  *
106
115
  * ```ts
107
- * import type { Refinement } from "@evolu/common";
116
+ * import { assert, assertEqual, type Refinement } from "@evolu/common";
108
117
  *
109
118
  * interface Animal {
110
119
  * readonly name: string;
@@ -117,9 +126,9 @@ export type PredicateWithIndex<T> = (value: T, index: number) => boolean;
117
126
  * "breed" in animal;
118
127
  * const dog: Dog = { name: "Dog", breed: "Beagle" };
119
128
  * const animal: Animal = dog;
120
- * if (!isDog(animal)) throw new Error("Expected a dog");
129
+ * assert(isDog(animal), "Expected a dog.");
121
130
  *
122
- * expect(animal.breed).toBe("Beagle");
131
+ * assertEqual(animal.breed, "Beagle");
123
132
  * ```
124
133
  */
125
134
  export type Refinement<in A, out B extends A> = (a: A) => a is B;
@@ -134,7 +143,12 @@ export type Refinement<in A, out B extends A> = (a: A) => a is B;
134
143
  * ### Indexed refinement
135
144
  *
136
145
  * ```ts
137
- * import { partitionArray, type RefinementWithIndex } from "@evolu/common";
146
+ * import {
147
+ * assertTrue,
148
+ * assertType,
149
+ * partitionArray,
150
+ * type RefinementWithIndex,
151
+ * } from "@evolu/common";
138
152
  *
139
153
  * type Item = {
140
154
  * readonly type: "number" | "string";
@@ -152,9 +166,9 @@ export type Refinement<in A, out B extends A> = (a: A) => a is B;
152
166
  * ];
153
167
  * const [numbers, others] = partitionArray(items, isNumberItem);
154
168
  *
155
- * expectTypeOf(numbers).toEqualTypeOf<ReadonlyArray<NumberItem>>();
156
- * expect(numbers[0]?.value).toBe(2);
157
- * expect(others[0]?.value).toBe(1);
169
+ * assertType<ReadonlyArray<NumberItem>, typeof numbers>();
170
+ * assertTrue(numbers[0]?.value === 2);
171
+ * assertTrue(others[0]?.value === 1);
158
172
  * ```
159
173
  */
160
174
  export type RefinementWithIndex<in A, out B extends A> = (
@@ -177,7 +191,7 @@ export type RefinementWithIndex<in A, out B extends A> = (
177
191
  * ### Adding runtime identity
178
192
  *
179
193
  * ```ts
180
- * import { instance, type Instance } from "@evolu/common";
194
+ * import { assertEqual, instance, type Instance } from "@evolu/common";
181
195
  *
182
196
  * interface Foo extends Instance<"Foo"> {
183
197
  * readonly value: string;
@@ -188,7 +202,7 @@ export type RefinementWithIndex<in A, out B extends A> = (
188
202
  * value: "value",
189
203
  * };
190
204
  *
191
- * expect(foo["~evolu/instance"]).toBe("Foo");
205
+ * assertEqual(foo["~evolu/instance"], "Foo");
192
206
  * ```
193
207
  */
194
208
  export interface Instance<Name extends string> {
@@ -212,7 +226,12 @@ export const instance = <const Name extends string>(
212
226
  * ### Checking runtime identity
213
227
  *
214
228
  * ```ts
215
- * import { instance, isInstance, type Instance } from "@evolu/common";
229
+ * import {
230
+ * assertTrue,
231
+ * instance,
232
+ * isInstance,
233
+ * type Instance,
234
+ * } from "@evolu/common";
216
235
  *
217
236
  * interface Foo extends Instance<"Foo"> {
218
237
  * readonly value: string;
@@ -221,7 +240,7 @@ export const instance = <const Name extends string>(
221
240
  * const isFoo = isInstance<Foo>("Foo");
222
241
  * const value: unknown = { ...instance("Foo"), value: "value" };
223
242
  *
224
- * expect(isFoo(value)).toBe(true);
243
+ * assertTrue(isFoo(value));
225
244
  * ```
226
245
  */
227
246
  export const isInstance =
@@ -241,17 +260,20 @@ export const isInstance =
241
260
  * ### Optional nullable properties
242
261
  *
243
262
  * ```ts
244
- * import type { NullablePartial } from "@evolu/common";
263
+ * import { assertType, type NullablePartial } from "@evolu/common";
245
264
  *
246
265
  * type Example = {
247
266
  * required: string;
248
267
  * optionalWithNull: string | null;
249
268
  * };
250
269
  *
251
- * expectTypeOf<NullablePartial<Example>>().toEqualTypeOf<{
252
- * required: string;
253
- * optionalWithNull?: string | null;
254
- * }>();
270
+ * assertType<
271
+ * {
272
+ * required: string;
273
+ * optionalWithNull?: string | null;
274
+ * },
275
+ * NullablePartial<Example>
276
+ * >();
255
277
  * ```
256
278
  */
257
279
  export type NullablePartial<
@@ -308,15 +330,18 @@ export type Writable<T> = {
308
330
  * ### Flattening an intersection
309
331
  *
310
332
  * ```ts
311
- * import type { Simplify } from "@evolu/common";
333
+ * import { assertType, type Simplify } from "@evolu/common";
312
334
  *
313
335
  * type A = { a: string } & { b: number };
314
336
  * type B = Simplify<A>;
315
337
  *
316
- * expectTypeOf<B>().toEqualTypeOf<{
317
- * a: string;
318
- * b: number;
319
- * }>();
338
+ * assertType<
339
+ * {
340
+ * a: string;
341
+ * b: number;
342
+ * },
343
+ * B
344
+ * >();
320
345
  * ```
321
346
  */
322
347
  export type Simplify<T> = {
@@ -339,7 +364,11 @@ export type PartialProp<T, K extends keyof T> = Omit<T, K> &
339
364
  * ### Sync and async completion
340
365
  *
341
366
  * ```ts
342
- * import { isPromiseLike, type Awaitable } from "@evolu/common";
367
+ * import {
368
+ * assertEqual,
369
+ * isPromiseLike,
370
+ * type Awaitable,
371
+ * } from "@evolu/common";
343
372
  *
344
373
  * const cache = new Map([["cached", "from cache"]]);
345
374
  * const getData = (id: string): Awaitable<string> =>
@@ -349,8 +378,8 @@ export type PartialProp<T, K extends keyof T> = Omit<T, K> &
349
378
  * const result = getData("cached");
350
379
  * const cached = isPromiseLike(result) ? await result : result;
351
380
  *
352
- * expect(fetched).toBe("fetched missing");
353
- * expect(cached).toBe("from cache");
381
+ * assertEqual(fetched, "fetched missing");
382
+ * assertEqual(cached, "from cache");
354
383
  * ```
355
384
  */
356
385
  export type Awaitable<T> = T | PromiseLike<T>;
@@ -364,7 +393,11 @@ export type Awaitable<T> = T | PromiseLike<T>;
364
393
  * ### Conditional awaiting
365
394
  *
366
395
  * ```ts
367
- * import { isPromiseLike, type Awaitable } from "@evolu/common";
396
+ * import {
397
+ * assertTrue,
398
+ * isPromiseLike,
399
+ * type Awaitable,
400
+ * } from "@evolu/common";
368
401
  *
369
402
  * const cache = new Map([["cached", true]]);
370
403
  * const validate = (id: string): Awaitable<boolean> =>
@@ -373,7 +406,7 @@ export type Awaitable<T> = T | PromiseLike<T>;
373
406
  * const result = validate("cached");
374
407
  * const isValid = isPromiseLike(result) ? await result : result;
375
408
  *
376
- * expect(isValid).toBe(true);
409
+ * assertTrue(isValid);
377
410
  * ```
378
411
  */
379
412
  export const isPromiseLike = <T>(
@@ -387,6 +420,40 @@ export type CompileTimeError<
387
420
  Message extends string,
388
421
  > = `⛔ ${Context} error: ${Message}`;
389
422
 
423
+ /**
424
+ * Returns whether two types are identical according to TypeScript.
425
+ *
426
+ * Unlike mutual assignability, this distinguishes narrower literals, `any`,
427
+ * `unknown`, `never`, optional properties, and readonly properties.
428
+ * Intersection types are not normalized; apply {@link Simplify} explicitly when
429
+ * normalization is part of the intended comparison.
430
+ *
431
+ * ### Exact type equality
432
+ *
433
+ * ```ts
434
+ * import { assertType, type IsSameType } from "@evolu/common";
435
+ *
436
+ * assertType<
437
+ * true,
438
+ * IsSameType<{ readonly id: string }, { readonly id: string }>
439
+ * >();
440
+ * assertType<false, IsSameType<"ready", string>>();
441
+ * ```
442
+ */
443
+ export type IsSameType<A, B> =
444
+ (<T>() => T extends (A & T) | T ? true : false) extends <T>() => T extends
445
+ (B & T) | T
446
+ ? true
447
+ : false
448
+ ? [A] extends [never]
449
+ ? [B] extends [never]
450
+ ? true
451
+ : false
452
+ : [B] extends [never]
453
+ ? false
454
+ : true
455
+ : false;
456
+
390
457
  /** Returns whether a type is a union. */
391
458
  export type IsUnion<T, Whole = T> = [T] extends [never]
392
459
  ? false
@@ -420,7 +487,7 @@ export type ParameterIntersection<T> = [T] extends [(value: infer I) => void]
420
487
  * ### Preserving discriminated unions
421
488
  *
422
489
  * ```ts
423
- * import type { DistributiveOmit } from "@evolu/common";
490
+ * import { assertType, type DistributiveOmit } from "@evolu/common";
424
491
  *
425
492
  * type Event =
426
493
  * | { type: "a"; a: string; shared: number }
@@ -428,8 +495,9 @@ export type ParameterIntersection<T> = [T] extends [(value: infer I) => void]
428
495
  *
429
496
  * type Payload = DistributiveOmit<Event, "shared">;
430
497
  *
431
- * expectTypeOf<Payload>().toEqualTypeOf<
432
- * { type: "a"; a: string } | { type: "b"; b: number }
498
+ * assertType<
499
+ * { type: "a"; a: string } | { type: "b"; b: number },
500
+ * Payload
433
501
  * >();
434
502
  * ```
435
503
  */
package/src/WebSocket.ts CHANGED
@@ -53,6 +53,10 @@ import { ArrayBuffer, String, Uint8Array, type Typed } from "./Type.ts";
53
53
  *
54
54
  * ```ts
55
55
  * import {
56
+ * assert,
57
+ * assertEqual,
58
+ * assertOk,
59
+ * assertTrue,
56
60
  * createRun,
57
61
  * createWebSocket,
58
62
  * testCreateWebSocket,
@@ -70,9 +74,6 @@ import { ArrayBuffer, String, Uint8Array, type Typed } from "./Type.ts";
70
74
  * createSocket("wss://example.com", {
71
75
  * protocols: ["evolu"],
72
76
  * binaryType: "arraybuffer",
73
- * onOpen: () => console.log("Connected"),
74
- * onMessage: (data) => console.log("Received:", data),
75
- * onClose: () => console.log("Disconnected"),
76
77
  * }),
77
78
  * );
78
79
  * return socket.send("Hello");
@@ -81,10 +82,17 @@ import { ArrayBuffer, String, Uint8Array, type Typed } from "./Type.ts";
81
82
  * const socketFactory = testCreateWebSocket();
82
83
  * await using run = createRun();
83
84
  *
84
- * expectOk(await run(connectAndSend(socketFactory)), undefined);
85
- * expect(socketFactory.sentMessages).toEqual([
85
+ * assertOk(await run(connectAndSend(socketFactory)), undefined);
86
+ * assertTrue(socketFactory.sentMessages.length === 1);
87
+ * const message = socketFactory.sentMessages[0];
88
+ * assert(
89
+ * message !== undefined && typeof message.data === "string",
90
+ * "Expected a text message.",
91
+ * );
92
+ * assertEqual(
93
+ * { url: message.url, data: message.data },
86
94
  * { url: "wss://example.com", data: "Hello" },
87
- * ]);
95
+ * );
88
96
  * ```
89
97
  */
90
98
  export interface WebSocket extends AsyncDisposable {
package/src/Worker.ts CHANGED
@@ -64,6 +64,7 @@ export interface MessagePort<Input, Output = never> extends Disposable {
64
64
  *
65
65
  * ```ts
66
66
  * import {
67
+ * assertType,
67
68
  * createMessageChannel,
68
69
  * type NativeMessagePort,
69
70
  * } from "@evolu/common";
@@ -79,9 +80,7 @@ export interface MessagePort<Input, Output = never> extends Disposable {
79
80
  * port: consoleChannel.port1.native,
80
81
  * };
81
82
  *
82
- * expectTypeOf(init.port).toEqualTypeOf<
83
- * NativeMessagePort<ConsoleMessage>
84
- * >();
83
+ * assertType<NativeMessagePort<ConsoleMessage>, typeof init.port>();
85
84
  * ```
86
85
  */
87
86
  readonly native: NativeMessagePort<Input, Output>;
@@ -146,6 +145,7 @@ export type WorkerDeps = ConsoleDep &
146
145
  *
147
146
  * ```ts
148
147
  * import {
148
+ * assertEqual,
149
149
  * createMessageChannel,
150
150
  * createMessagePort,
151
151
  * createSharedWorker,
@@ -183,14 +183,18 @@ export type WorkerDeps = ConsoleDep &
183
183
  * ]);
184
184
  * queryChannel.port1.postMessage({ text: "all todos" });
185
185
  *
186
- * expect(await response.promise).toEqual({ rows: ["all todos"] });
186
+ * assertEqual(await response.promise, { rows: ["all todos"] });
187
187
  * ```
188
188
  *
189
189
  * On the worker side, attach the handler after asynchronous initialization;
190
190
  * messages sent earlier remain queued:
191
191
  *
192
192
  * ```ts
193
- * import { createMessageChannel, createMessagePort } from "@evolu/common";
193
+ * import {
194
+ * assertEqual,
195
+ * createMessageChannel,
196
+ * createMessagePort,
197
+ * } from "@evolu/common";
194
198
  *
195
199
  * interface Query {
196
200
  * readonly text: string;
@@ -211,7 +215,7 @@ export type WorkerDeps = ConsoleDep &
211
215
  * };
212
216
  * await allReceived.promise;
213
217
  *
214
- * expect(received).toEqual([
218
+ * assertEqual(received, [
215
219
  * { text: "all todos" },
216
220
  * { text: "completed todos" },
217
221
  * ]);
package/src/intl/_en.ts CHANGED
@@ -39,6 +39,7 @@ import type {
39
39
  LessThanError,
40
40
  LessThanOrEqualToError,
41
41
  LiteralError,
42
+ MapError,
42
43
  MaxLengthError,
43
44
  MinLengthError,
44
45
  MnemonicError,
@@ -345,10 +346,6 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
345
346
  if (error.reason.kind === "NotSet") {
346
347
  return `A value ${safelyStringifyUnknownValue(error.reason.value)} is not a Set.`;
347
348
  }
348
- if (error.reason.kind === "UnexpectedPrototype") {
349
- return "The value is an instance of a Set subclass, but a Set Output must be a direct Set instance.";
350
- }
351
-
352
349
  const issue = error.reason.issues[0];
353
350
 
354
351
  switch (issue.kind) {
@@ -359,6 +356,25 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
359
356
  }
360
357
  };
361
358
 
359
+ /** Formats a MapError in English. */
360
+ export const formatMapError: TypeErrorFormatter<MapError> = (error) => {
361
+ if (error.reason.kind === "NotMap") {
362
+ return `A value ${safelyStringifyUnknownValue(error.reason.value)} is not a Map.`;
363
+ }
364
+ const issue = error.reason.issues[0];
365
+
366
+ switch (issue.kind) {
367
+ case "ExcessProperty":
368
+ return `An excess Map property ${safelyStringifyUnknownValue(issue.key)} is not allowed.`;
369
+ case "Key":
370
+ return `A Map key at index ${issue.index} is invalid.`;
371
+ case "Value":
372
+ return `A Map value at index ${issue.index} is invalid.`;
373
+ case "Collision":
374
+ return `Map keys at indexes ${issue.previousIndex} and ${issue.index} decode to the same key ${safelyStringifyUnknownValue(issue.outputKey)}.`;
375
+ }
376
+ };
377
+
362
378
  /** Formats a TupleError in English. */
363
379
  export const formatTupleError: TypeErrorFormatter<
364
380
  TupleError | TupleElementsError<TypeError>
package/src/intl/ar.ts CHANGED
@@ -30,6 +30,7 @@ import type {
30
30
  LessThanError,
31
31
  LessThanOrEqualToError,
32
32
  LiteralError,
33
+ MapError,
33
34
  MaxLengthError,
34
35
  MinLengthError,
35
36
  MnemonicError,
@@ -285,8 +286,6 @@ export const formatArrayError: TypeErrorFormatter<ArrayError> = (error) => {
285
286
  export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
286
287
  if (error.reason.kind === "NotSet")
287
288
  return `القيمة ${safelyStringifyUnknownValue(error.reason.value)} ليست Set.`;
288
- if (error.reason.kind === "UnexpectedPrototype")
289
- return "القيمة مثيل لفئة فرعية من Set، لكن مخرج Set يجب أن يكون مثيل Set مباشراً.";
290
289
  const issue = error.reason.issues[0];
291
290
  switch (issue.kind) {
292
291
  case "ExcessProperty":
@@ -296,6 +295,22 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
296
295
  }
297
296
  };
298
297
 
298
+ /** Formats a MapError in Arabic. */
299
+ export const formatMapError: TypeErrorFormatter<MapError> = (error) => {
300
+ if (error.reason.kind === "NotMap")
301
+ return `القيمة ${safelyStringifyUnknownValue(error.reason.value)} ليست Map.`;
302
+ const issue = error.reason.issues[0];
303
+ switch (issue.kind) {
304
+ case "ExcessProperty":
305
+ return `خاصية Map زائدة ${safelyStringifyUnknownValue(issue.key)} غير مسموح بها.`;
306
+ case "Key":
307
+ case "Value":
308
+ return `عنصر Map عند الفهرس ${issue.index} غير صالح.`;
309
+ case "Collision":
310
+ return `مفتاحا Map ${safelyStringifyUnknownValue(issue.previousKey)} و${safelyStringifyUnknownValue(issue.key)} يُفك ترميزهما إلى المفتاح نفسه ${safelyStringifyUnknownValue(issue.outputKey)}.`;
311
+ }
312
+ };
313
+
299
314
  /** Formats a TupleError in Arabic. */
300
315
  export const formatTupleError: TypeErrorFormatter<
301
316
  TupleError | TupleElementsError<TypeError>
package/src/intl/bn.ts CHANGED
@@ -30,6 +30,7 @@ import type {
30
30
  LessThanError,
31
31
  LessThanOrEqualToError,
32
32
  LiteralError,
33
+ MapError,
33
34
  MaxLengthError,
34
35
  MinLengthError,
35
36
  MnemonicError,
@@ -334,10 +335,6 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
334
335
  if (error.reason.kind === "NotSet") {
335
336
  return `${safelyStringifyUnknownValue(error.reason.value)} মানটি Set নয়।`;
336
337
  }
337
- if (error.reason.kind === "UnexpectedPrototype") {
338
- return "মানটি Set subclass-এর instance, কিন্তু Set Output অবশ্যই সরাসরি Set instance হতে হবে।";
339
- }
340
-
341
338
  const issue = error.reason.issues[0];
342
339
 
343
340
  switch (issue.kind) {
@@ -348,6 +345,24 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
348
345
  }
349
346
  };
350
347
 
348
+ /** Formats a MapError in Bengali. */
349
+ export const formatMapError: TypeErrorFormatter<MapError> = (error) => {
350
+ if (error.reason.kind === "NotMap") {
351
+ return `${safelyStringifyUnknownValue(error.reason.value)} মানটি Map নয়।`;
352
+ }
353
+ const issue = error.reason.issues[0];
354
+
355
+ switch (issue.kind) {
356
+ case "ExcessProperty":
357
+ return `অতিরিক্ত Map property ${safelyStringifyUnknownValue(issue.key)} অনুমোদিত নয়।`;
358
+ case "Key":
359
+ case "Value":
360
+ return `Map-এর index ${issue.index}-এর element অবৈধ।`;
361
+ case "Collision":
362
+ return `Map key ${safelyStringifyUnknownValue(issue.previousKey)} এবং ${safelyStringifyUnknownValue(issue.key)} decode হয়ে একই key ${safelyStringifyUnknownValue(issue.outputKey)} হয়।`;
363
+ }
364
+ };
365
+
351
366
  /** Formats a TupleError in Bengali. */
352
367
  export const formatTupleError: TypeErrorFormatter<
353
368
  TupleError | TupleElementsError<TypeError>
package/src/intl/ca.ts CHANGED
@@ -30,6 +30,7 @@ import type {
30
30
  LessThanError,
31
31
  LessThanOrEqualToError,
32
32
  LiteralError,
33
+ MapError,
33
34
  MaxLengthError,
34
35
  MinLengthError,
35
36
  MnemonicError,
@@ -336,10 +337,6 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
336
337
  if (error.reason.kind === "NotSet") {
337
338
  return `El valor ${safelyStringifyUnknownValue(error.reason.value)} no és un Set.`;
338
339
  }
339
- if (error.reason.kind === "UnexpectedPrototype") {
340
- return "El valor és una instància d’una subclasse de Set, però l’Output de Set ha de ser una instància directa de Set.";
341
- }
342
-
343
340
  const issue = error.reason.issues[0];
344
341
 
345
342
  switch (issue.kind) {
@@ -350,6 +347,24 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
350
347
  }
351
348
  };
352
349
 
350
+ /** Formata MapError en català. */
351
+ export const formatMapError: TypeErrorFormatter<MapError> = (error) => {
352
+ if (error.reason.kind === "NotMap") {
353
+ return `El valor ${safelyStringifyUnknownValue(error.reason.value)} no és un Map.`;
354
+ }
355
+ const issue = error.reason.issues[0];
356
+
357
+ switch (issue.kind) {
358
+ case "ExcessProperty":
359
+ return `No es permet la propietat Map addicional ${safelyStringifyUnknownValue(issue.key)}.`;
360
+ case "Key":
361
+ case "Value":
362
+ return `L’element de Map a l’índex ${issue.index} no és vàlid.`;
363
+ case "Collision":
364
+ return `Les claus de Map ${safelyStringifyUnknownValue(issue.previousKey)} i ${safelyStringifyUnknownValue(issue.key)} es descodifiquen a la mateixa clau ${safelyStringifyUnknownValue(issue.outputKey)}.`;
365
+ }
366
+ };
367
+
353
368
  /** Formata TupleError en català. */
354
369
  export const formatTupleError: TypeErrorFormatter<
355
370
  TupleError | TupleElementsError<TypeError>
package/src/intl/cs.ts CHANGED
@@ -30,6 +30,7 @@ import type {
30
30
  LessThanError,
31
31
  LessThanOrEqualToError,
32
32
  LiteralError,
33
+ MapError,
33
34
  MaxLengthError,
34
35
  MinLengthError,
35
36
  MnemonicError,
@@ -335,10 +336,6 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
335
336
  if (error.reason.kind === "NotSet") {
336
337
  return `Hodnota ${safelyStringifyUnknownValue(error.reason.value)} není Set.`;
337
338
  }
338
- if (error.reason.kind === "UnexpectedPrototype") {
339
- return "Hodnota je instancí podtřídy Setu, ale Output typu Set musí být přímou instancí Setu.";
340
- }
341
-
342
339
  const issue = error.reason.issues[0];
343
340
 
344
341
  switch (issue.kind) {
@@ -349,6 +346,24 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
349
346
  }
350
347
  };
351
348
 
349
+ /** Formats a MapError in Czech. */
350
+ export const formatMapError: TypeErrorFormatter<MapError> = (error) => {
351
+ if (error.reason.kind === "NotMap") {
352
+ return `Hodnota ${safelyStringifyUnknownValue(error.reason.value)} není Map.`;
353
+ }
354
+ const issue = error.reason.issues[0];
355
+
356
+ switch (issue.kind) {
357
+ case "ExcessProperty":
358
+ return `Map obsahuje nepovolenou vlastní vlastnost ${safelyStringifyUnknownValue(issue.key)}.`;
359
+ case "Key":
360
+ case "Value":
361
+ return `Prvek Mapu na indexu ${issue.index} není platný.`;
362
+ case "Collision":
363
+ return `Klíče Mapu ${safelyStringifyUnknownValue(issue.previousKey)} a ${safelyStringifyUnknownValue(issue.key)} se dekódují na stejný klíč ${safelyStringifyUnknownValue(issue.outputKey)}.`;
364
+ }
365
+ };
366
+
352
367
  /** Formats a TupleError in Czech. */
353
368
  export const formatTupleError: TypeErrorFormatter<
354
369
  TupleError | TupleElementsError<TypeError>
package/src/intl/da.ts CHANGED
@@ -30,6 +30,7 @@ import type {
30
30
  LessThanError,
31
31
  LessThanOrEqualToError,
32
32
  LiteralError,
33
+ MapError,
33
34
  MaxLengthError,
34
35
  MinLengthError,
35
36
  MnemonicError,
@@ -336,10 +337,6 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
336
337
  if (error.reason.kind === "NotSet") {
337
338
  return `Værdien ${safelyStringifyUnknownValue(error.reason.value)} er ikke et Set.`;
338
339
  }
339
- if (error.reason.kind === "UnexpectedPrototype") {
340
- return "Værdien er en instans af en Set-underklasse, men et Set Output skal være en direkte Set-instans.";
341
- }
342
-
343
340
  const issue = error.reason.issues[0];
344
341
 
345
342
  switch (issue.kind) {
@@ -350,6 +347,24 @@ export const formatSetError: TypeErrorFormatter<SetError> = (error) => {
350
347
  }
351
348
  };
352
349
 
350
+ /** Formaterer MapError på dansk. */
351
+ export const formatMapError: TypeErrorFormatter<MapError> = (error) => {
352
+ if (error.reason.kind === "NotMap") {
353
+ return `Værdien ${safelyStringifyUnknownValue(error.reason.value)} er ikke et Map.`;
354
+ }
355
+ const issue = error.reason.issues[0];
356
+
357
+ switch (issue.kind) {
358
+ case "ExcessProperty":
359
+ return `Den ekstra Map-egenskab ${safelyStringifyUnknownValue(issue.key)} er ikke tilladt.`;
360
+ case "Key":
361
+ case "Value":
362
+ return `Et Map-element på indeks ${issue.index} er ugyldigt.`;
363
+ case "Collision":
364
+ return `Map-nøglerne ${safelyStringifyUnknownValue(issue.previousKey)} og ${safelyStringifyUnknownValue(issue.key)} afkodes til den samme nøgle ${safelyStringifyUnknownValue(issue.outputKey)}.`;
365
+ }
366
+ };
367
+
353
368
  /** Formaterer TupleError på dansk. */
354
369
  export const formatTupleError: TypeErrorFormatter<
355
370
  TupleError | TupleElementsError<TypeError>