@evolu/common 8.2.0 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/Function.d.ts +1 -0
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Http.d.ts +9 -0
- package/dist/src/Http.d.ts.map +1 -1
- package/dist/src/Object.d.ts +1 -0
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/RefCount.d.ts +1 -0
- package/dist/src/RefCount.d.ts.map +1 -1
- package/dist/src/Relation.d.ts +2 -0
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Resource.d.ts +1 -0
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Result.d.ts +383 -548
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +296 -46
- package/dist/src/StackTrace.d.ts +1 -0
- package/dist/src/StackTrace.d.ts.map +1 -1
- package/dist/src/Task.d.ts +985 -1069
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1007 -156
- package/dist/src/Time.d.ts +1 -0
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Type.d.ts +1285 -734
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +1057 -193
- package/dist/src/intl/_en.d.ts +126 -0
- package/dist/src/intl/_en.d.ts.map +1 -0
- package/dist/src/intl/_en.js +267 -0
- package/dist/src/intl/ar.d.ts +117 -0
- package/dist/src/intl/ar.d.ts.map +1 -0
- package/dist/src/intl/ar.js +245 -0
- package/dist/src/intl/bn.d.ts +117 -0
- package/dist/src/intl/bn.d.ts.map +1 -0
- package/dist/src/intl/bn.js +258 -0
- package/dist/src/intl/ca.d.ts +117 -0
- package/dist/src/intl/ca.d.ts.map +1 -0
- package/dist/src/intl/ca.js +258 -0
- package/dist/src/intl/cs.d.ts +20 -7
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +54 -27
- package/dist/src/intl/da.d.ts +117 -0
- package/dist/src/intl/da.d.ts.map +1 -0
- package/dist/src/intl/da.js +258 -0
- package/dist/src/intl/de.d.ts +117 -0
- package/dist/src/intl/de.d.ts.map +1 -0
- package/dist/src/intl/de.js +258 -0
- package/dist/src/intl/el.d.ts +117 -0
- package/dist/src/intl/el.d.ts.map +1 -0
- package/dist/src/intl/el.js +265 -0
- package/dist/src/intl/es.d.ts +117 -0
- package/dist/src/intl/es.d.ts.map +1 -0
- package/dist/src/intl/es.js +258 -0
- package/dist/src/intl/fa.d.ts +117 -0
- package/dist/src/intl/fa.d.ts.map +1 -0
- package/dist/src/intl/fa.js +258 -0
- package/dist/src/intl/fi.d.ts +117 -0
- package/dist/src/intl/fi.d.ts.map +1 -0
- package/dist/src/intl/fi.js +258 -0
- package/dist/src/intl/fil.d.ts +117 -0
- package/dist/src/intl/fil.d.ts.map +1 -0
- package/dist/src/intl/fil.js +258 -0
- package/dist/src/intl/fr.d.ts +117 -0
- package/dist/src/intl/fr.d.ts.map +1 -0
- package/dist/src/intl/fr.js +258 -0
- package/dist/src/intl/he.d.ts +117 -0
- package/dist/src/intl/he.d.ts.map +1 -0
- package/dist/src/intl/he.js +258 -0
- package/dist/src/intl/hi.d.ts +117 -0
- package/dist/src/intl/hi.d.ts.map +1 -0
- package/dist/src/intl/hi.js +258 -0
- package/dist/src/intl/hr.d.ts +117 -0
- package/dist/src/intl/hr.d.ts.map +1 -0
- package/dist/src/intl/hr.js +265 -0
- package/dist/src/intl/hu.d.ts +63 -0
- package/dist/src/intl/hu.d.ts.map +1 -0
- package/dist/src/intl/hu.js +204 -0
- package/dist/src/intl/id.d.ts +117 -0
- package/dist/src/intl/id.d.ts.map +1 -0
- package/dist/src/intl/id.js +258 -0
- package/dist/src/intl/index.d.ts +42 -0
- package/dist/src/intl/index.d.ts.map +1 -1
- package/dist/src/intl/index.js +42 -0
- package/dist/src/intl/it.d.ts +117 -0
- package/dist/src/intl/it.d.ts.map +1 -0
- package/dist/src/intl/it.js +258 -0
- package/dist/src/intl/ja.d.ts +117 -0
- package/dist/src/intl/ja.d.ts.map +1 -0
- package/dist/src/intl/ja.js +258 -0
- package/dist/src/intl/ko.d.ts +117 -0
- package/dist/src/intl/ko.d.ts.map +1 -0
- package/dist/src/intl/ko.js +258 -0
- package/dist/src/intl/ml.d.ts +117 -0
- package/dist/src/intl/ml.d.ts.map +1 -0
- package/dist/src/intl/ml.js +258 -0
- package/dist/src/intl/mr.d.ts +117 -0
- package/dist/src/intl/mr.d.ts.map +1 -0
- package/dist/src/intl/mr.js +258 -0
- package/dist/src/intl/ms.d.ts +117 -0
- package/dist/src/intl/ms.d.ts.map +1 -0
- package/dist/src/intl/ms.js +245 -0
- package/dist/src/intl/nb.d.ts +63 -0
- package/dist/src/intl/nb.d.ts.map +1 -0
- package/dist/src/intl/nb.js +191 -0
- package/dist/src/intl/nl.d.ts +117 -0
- package/dist/src/intl/nl.d.ts.map +1 -0
- package/dist/src/intl/nl.js +258 -0
- package/dist/src/intl/pa.d.ts +117 -0
- package/dist/src/intl/pa.d.ts.map +1 -0
- package/dist/src/intl/pa.js +258 -0
- package/dist/src/intl/pl.d.ts +117 -0
- package/dist/src/intl/pl.d.ts.map +1 -0
- package/dist/src/intl/pl.js +242 -0
- package/dist/src/intl/pt-BR.d.ts +117 -0
- package/dist/src/intl/pt-BR.d.ts.map +1 -0
- package/dist/src/intl/pt-BR.js +258 -0
- package/dist/src/intl/pt.d.ts +117 -0
- package/dist/src/intl/pt.d.ts.map +1 -0
- package/dist/src/intl/pt.js +246 -0
- package/dist/src/intl/ro.d.ts +117 -0
- package/dist/src/intl/ro.d.ts.map +1 -0
- package/dist/src/intl/ro.js +258 -0
- package/dist/src/intl/sk.d.ts +117 -0
- package/dist/src/intl/sk.d.ts.map +1 -0
- package/dist/src/intl/sk.js +244 -0
- package/dist/src/intl/sl.d.ts +117 -0
- package/dist/src/intl/sl.d.ts.map +1 -0
- package/dist/src/intl/sl.js +258 -0
- package/dist/src/intl/sv.d.ts +117 -0
- package/dist/src/intl/sv.d.ts.map +1 -0
- package/dist/src/intl/sv.js +258 -0
- package/dist/src/intl/sw.d.ts +63 -0
- package/dist/src/intl/sw.d.ts.map +1 -0
- package/dist/src/intl/sw.js +191 -0
- package/dist/src/intl/ta.d.ts +117 -0
- package/dist/src/intl/ta.d.ts.map +1 -0
- package/dist/src/intl/ta.js +258 -0
- package/dist/src/intl/te.d.ts +117 -0
- package/dist/src/intl/te.d.ts.map +1 -0
- package/dist/src/intl/te.js +258 -0
- package/dist/src/intl/th.d.ts +117 -0
- package/dist/src/intl/th.d.ts.map +1 -0
- package/dist/src/intl/th.js +258 -0
- package/dist/src/intl/tr.d.ts +117 -0
- package/dist/src/intl/tr.d.ts.map +1 -0
- package/dist/src/intl/tr.js +255 -0
- package/dist/src/intl/uk.d.ts +117 -0
- package/dist/src/intl/uk.d.ts.map +1 -0
- package/dist/src/intl/uk.js +258 -0
- package/dist/src/intl/ur.d.ts +117 -0
- package/dist/src/intl/ur.d.ts.map +1 -0
- package/dist/src/intl/ur.js +245 -0
- package/dist/src/intl/vi.d.ts +117 -0
- package/dist/src/intl/vi.d.ts.map +1 -0
- package/dist/src/intl/vi.js +255 -0
- package/dist/src/intl/zh-CN.d.ts +117 -0
- package/dist/src/intl/zh-CN.d.ts.map +1 -0
- package/dist/src/intl/zh-CN.js +258 -0
- package/dist/src/intl/zh-TW.d.ts +117 -0
- package/dist/src/intl/zh-TW.d.ts.map +1 -0
- package/dist/src/intl/zh-TW.js +258 -0
- package/dist/src/local-first/Owner.d.ts +156 -62
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +119 -20
- package/package.json +1 -1
- package/src/Function.ts +2 -0
- package/src/Http.ts +9 -0
- package/src/Object.ts +2 -0
- package/src/RefCount.ts +2 -0
- package/src/Relation.ts +4 -0
- package/src/Resource.ts +2 -0
- package/src/Result.ts +397 -560
- package/src/StackTrace.ts +2 -0
- package/src/Task.ts +1143 -1222
- package/src/Time.ts +2 -0
- package/src/Type.ts +1598 -712
- package/src/intl/_en.ts +497 -0
- package/src/intl/ar.ts +417 -0
- package/src/intl/bn.ts +486 -0
- package/src/intl/ca.ts +488 -0
- package/src/intl/cs.ts +95 -31
- package/src/intl/da.ts +488 -0
- package/src/intl/de.ts +488 -0
- package/src/intl/el.ts +494 -0
- package/src/intl/es.ts +488 -0
- package/src/intl/fa.ts +487 -0
- package/src/intl/fi.ts +487 -0
- package/src/intl/fil.ts +488 -0
- package/src/intl/fr.ts +488 -0
- package/src/intl/he.ts +486 -0
- package/src/intl/hi.ts +487 -0
- package/src/intl/hr.ts +494 -0
- package/src/intl/hu.ts +387 -0
- package/src/intl/id.ts +487 -0
- package/src/intl/index.ts +42 -0
- package/src/intl/it.ts +488 -0
- package/src/intl/ja.ts +488 -0
- package/src/intl/ko.ts +487 -0
- package/src/intl/ml.ts +487 -0
- package/src/intl/mr.ts +487 -0
- package/src/intl/ms.ts +410 -0
- package/src/intl/nb.ts +364 -0
- package/src/intl/nl.ts +488 -0
- package/src/intl/pa.ts +487 -0
- package/src/intl/pl.ts +450 -0
- package/src/intl/pt-BR.ts +487 -0
- package/src/intl/pt.ts +424 -0
- package/src/intl/ro.ts +488 -0
- package/src/intl/sk.ts +412 -0
- package/src/intl/sl.ts +487 -0
- package/src/intl/sv.ts +488 -0
- package/src/intl/sw.ts +324 -0
- package/src/intl/ta.ts +487 -0
- package/src/intl/te.ts +487 -0
- package/src/intl/th.ts +484 -0
- package/src/intl/tr.ts +487 -0
- package/src/intl/uk.ts +488 -0
- package/src/intl/ur.ts +410 -0
- package/src/intl/vi.ts +435 -0
- package/src/intl/zh-CN.ts +482 -0
- package/src/intl/zh-TW.ts +482 -0
- package/src/local-first/Owner.ts +156 -62
package/dist/src/Type.d.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime types.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
1
|
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
7
2
|
import type { AtLeastTwoReadonlyArray, NonEmptyReadonlyArray } from "./Array.ts";
|
|
8
3
|
import type { Brand } from "./Brand.ts";
|
|
@@ -12,359 +7,12 @@ import { type Result } from "./Result.ts";
|
|
|
12
7
|
import type { TimeDep } from "./Time.ts";
|
|
13
8
|
import { type CompileTimeError, type IsUnion, type Literal, type Simplify, type ValueWithLength, type WidenLiteral } from "./Types.ts";
|
|
14
9
|
/**
|
|
15
|
-
* A runtime representation of a TypeScript type
|
|
16
|
-
*
|
|
17
|
-
* Evolu Type reports expected decoding failures through {@link Result} rather
|
|
18
|
-
* than exceptions. It represents both an encoded `Input` and its semantic
|
|
19
|
-
* `Output`, supporting validation, transformation, and canonical encoding.
|
|
20
|
-
*
|
|
21
|
-
* Evolu Type is designed for correctness and developer experience. Correctness
|
|
22
|
-
* is especially important for local-first data: application authors cannot
|
|
23
|
-
* inspect or repair a user's data on a server because they do not have access
|
|
24
|
-
* to it. Type declarations must reject invalid data at system boundaries, then
|
|
25
|
-
* preserve those guarantees wherever the data travels.
|
|
26
|
-
*
|
|
27
|
-
* To make correct code the easiest code to write, Evolu Type preserves as much
|
|
28
|
-
* information as TypeScript can express. Invalid declarations produce readable
|
|
29
|
-
* {@link CompileTimeError} types when the compiler can detect them, while
|
|
30
|
-
* runtime assertions enforce construction contracts it cannot prove. Together,
|
|
31
|
-
* these choices create a pit of success.
|
|
32
|
-
*
|
|
33
|
-
* The implementation is optimized for minimal bundle size. Less descriptive
|
|
34
|
-
* assertion messages could make it even smaller, but Evolu keeps actionable
|
|
35
|
-
* messages as a deliberate tradeoff for developer experience.
|
|
36
|
-
*
|
|
37
|
-
* The main properties of Evolu Type are:
|
|
38
|
-
*
|
|
39
|
-
* - **Result-based error handling** – expected failures are explicit values.
|
|
40
|
-
* - **Typed errors with decoupled formatters** – validation logic stays
|
|
41
|
-
* independent of user-facing messages, and errors can be handled
|
|
42
|
-
* exhaustively.
|
|
43
|
-
* - **Type-safe, tree-shakeable localization** – formatter requirements are
|
|
44
|
-
* inferred from selected Types, while apps bundle exactly the locales they
|
|
45
|
-
* support so users can change language offline.
|
|
46
|
-
* - **Consistent constraints through {@link Brand}** – every refinement constraint
|
|
47
|
-
* is represented in the TypeScript type, so an unconstrained parent value
|
|
48
|
-
* cannot be used where the constrained value is required.
|
|
49
|
-
* - **Typed inputs** – prefer `from` and its `.parent` entry points to connect
|
|
50
|
-
* precise producer and consumer contracts while preserving typed remaining
|
|
51
|
-
* errors; reserve `fromUnknown` for genuinely unknown values.
|
|
52
|
-
* - **Lawful codecs** – Types partially decode `Input` to `Output` and totally
|
|
53
|
-
* encode every legitimate `Output` to `CanonicalInput`, the statically known
|
|
54
|
-
* subtype of `Input` returned by complete encoding.
|
|
55
|
-
* - **A top-down implementation** – the source is intended to be read from
|
|
56
|
-
* beginning to end.
|
|
57
|
-
*
|
|
58
|
-
* Evolu Type supports [Standard Schema](https://standardschema.dev/) for
|
|
59
|
-
* interoperability with compatible tools and frameworks while preserving each
|
|
60
|
-
* Type's exact Input and Output.
|
|
61
|
-
*
|
|
62
|
-
* Evolu Type assumes that all executing code, including third-party
|
|
63
|
-
* dependencies, has been audited and is trusted. It validates data contracts
|
|
64
|
-
* under that assumption. Trusting code does not require trusting every value it
|
|
65
|
-
* returns, so uncertain values from legacy code or another realm can still be
|
|
66
|
-
* decoded at an explicit boundary. It does not protect against hostile
|
|
67
|
-
* executable behavior such as sabotaged Proxies or throwing traps; Type
|
|
68
|
-
* validation is not a security boundary for untrusted JavaScript.
|
|
69
|
-
*
|
|
70
|
-
* Type declarations and their callbacks are trusted construction code. Evolu
|
|
71
|
-
* Type leverages that trust for better developer experience and does not try to
|
|
72
|
-
* recover from code that defeats the type system with `any` or casts, including
|
|
73
|
-
* fabricating an `Err` for `Result<_, never>`. Runtime assertions still enforce
|
|
74
|
-
* contracts TypeScript cannot express, and every Type declaration must be
|
|
75
|
-
* tested for its expected successes and failures.
|
|
76
|
-
*
|
|
77
|
-
* `fromUnknown` validates untyped input through the complete pipeline. `from`
|
|
78
|
-
* and its `.parent` operations use their declared boundary to determine which
|
|
79
|
-
* remaining stages can return validation errors, but assert that boundary at
|
|
80
|
-
* runtime. `orThrow` and `orNull` reuse the deepest `from` operation accepting
|
|
81
|
-
* `Input`, while `to` asserts its Output boundary. A failed assertion means
|
|
82
|
-
* application code violated its static contract; it is a developer error, not
|
|
83
|
-
* an expected validation failure. Its message identifies the expected Type and
|
|
84
|
-
* its cause preserves the exact structured Output validation error.
|
|
85
|
-
*
|
|
86
|
-
* Prefer the most precise typed boundary available. A value is not unknown
|
|
87
|
-
* merely because it originated outside the application: forms, components, and
|
|
88
|
-
* other producers often expose a `string` or a branded value that can connect
|
|
89
|
-
* directly to a matching `from` boundary. Reserve `fromUnknown` for values
|
|
90
|
-
* whose TypeScript type is genuinely `unknown`. `is` means exact membership in
|
|
91
|
-
* the output domain, not merely that output-side parsing could succeed. A
|
|
92
|
-
* successful `fromUnknown` result always satisfies `is`.
|
|
93
|
-
*
|
|
94
|
-
* Decoding accepts a representation outside the Output domain only when the
|
|
95
|
-
* Type explicitly declares that representation, such as a transformation Input.
|
|
96
|
-
* Structural Types do not implicitly repair another JavaScript representation.
|
|
97
|
-
* In particular, {@link array} and {@link tuple} require dense own data elements,
|
|
98
|
-
* while the predefined {@link Object}, {@link object}, and {@link record} require
|
|
99
|
-
* plain objects with own enumerable data properties. They do not invoke
|
|
100
|
-
* accessors or materialize inherited and non-enumerable properties.
|
|
101
|
-
*
|
|
102
|
-
* TypeScript object types are structural and do not encode JavaScript realm
|
|
103
|
-
* identity. Structural Types therefore accept legitimate representations from
|
|
104
|
-
* other realms. Prototype checks remain when the prototype defines the semantic
|
|
105
|
-
* domain. Plain-object Types accept a `null` prototype or an immediate root
|
|
106
|
-
* prototype whose own prototype is `null`; ordinary class instances and deeper
|
|
107
|
-
* prototype chains are rejected. When Record decoding must construct a
|
|
108
|
-
* normalized value, it uses a `null` prototype so every string key remains
|
|
109
|
-
* ordinary data.
|
|
110
|
-
*
|
|
111
|
-
* Evolu Type requires TypeScript 7 or newer and expects the
|
|
112
|
-
* `exactOptionalPropertyTypes` compiler option to be enabled.
|
|
113
|
-
*
|
|
114
|
-
* Predefined Types intentionally use the names of corresponding JavaScript
|
|
115
|
-
* built-ins because they represent those familiar value categories. If an
|
|
116
|
-
* imported Type shadows a built-in in the same scope, access the built-in
|
|
117
|
-
* through `globalThis`, JavaScript's standard cross-environment global object,
|
|
118
|
-
* such as `globalThis.String` or `globalThis.Date`.
|
|
119
|
-
*
|
|
120
|
-
* ### Example
|
|
121
|
-
*
|
|
122
|
-
* ```ts
|
|
123
|
-
* import { String, type Result } from "@evolu/common";
|
|
124
|
-
*
|
|
125
|
-
* const value: unknown = "hello";
|
|
126
|
-
* const result = String.fromUnknown(value);
|
|
127
|
-
*
|
|
128
|
-
* expectTypeOf(result).toEqualTypeOf<
|
|
129
|
-
* Result<
|
|
130
|
-
* string,
|
|
131
|
-
* {
|
|
132
|
-
* readonly type: "TypeOf";
|
|
133
|
-
* readonly expected: "String";
|
|
134
|
-
* readonly value: unknown;
|
|
135
|
-
* }
|
|
136
|
-
* >
|
|
137
|
-
* >();
|
|
138
|
-
* expectOk(result, "hello");
|
|
139
|
-
* ```
|
|
140
|
-
*
|
|
141
|
-
* ## FAQ
|
|
142
|
-
*
|
|
143
|
-
* ### What does a Type represent?
|
|
144
|
-
*
|
|
145
|
-
* A Type is a lawful, pure codec for an exact semantic domain:
|
|
146
|
-
*
|
|
147
|
-
* ```text
|
|
148
|
-
* Input ── partial decode ──▶ Output
|
|
149
|
-
* CanonicalInput ◀─── total encode ─── Output
|
|
150
|
-
*
|
|
151
|
-
* CanonicalInput ⊆ Input
|
|
152
|
-
* ```
|
|
153
|
-
*
|
|
154
|
-
* Read each line in the direction of its arrowhead. `Input` is the complete
|
|
155
|
-
* typed decoding boundary, including candidates that validation can reject and
|
|
156
|
-
* noncanonical representations that decoding can normalize. `Output` is the
|
|
157
|
-
* validated semantic value. `CanonicalInput` is the statically known subtype of
|
|
158
|
-
* `Input` returned by the complete `to` operation. It can be wider than the
|
|
159
|
-
* values actually emitted when a refinement follows an arbitrary transformation
|
|
160
|
-
* because TypeScript cannot determine which values its encoder returns for the
|
|
161
|
-
* narrowed Output. `fromUnknown` and the `from` operations decode; `to`
|
|
162
|
-
* encodes.
|
|
163
|
-
*
|
|
164
|
-
* A lawful Type round-trips every Output:
|
|
165
|
-
*
|
|
166
|
-
* ```text
|
|
167
|
-
* fromUnknown(to(output)) ≈ ok(output)
|
|
168
|
-
* ```
|
|
169
|
-
*
|
|
170
|
-
* Encoding can canonicalize a valid Input:
|
|
171
|
-
*
|
|
172
|
-
* ```text
|
|
173
|
-
* "0042" ──decode──▶ 42 ──encode──▶ "42"
|
|
174
|
-
* ```
|
|
175
|
-
*
|
|
176
|
-
* Once canonicalized, repeating the decode-encode cycle must preserve that
|
|
177
|
-
* representation:
|
|
178
|
-
*
|
|
179
|
-
* ```text
|
|
180
|
-
* "42" ──decode──▶ 42 ──encode──▶ "42"
|
|
181
|
-
* ```
|
|
182
|
-
*
|
|
183
|
-
* Here `decode` means running the complete decoding pipeline, as `fromUnknown`
|
|
184
|
-
* does, and `≈` means equality appropriate for the semantic domain. Validation
|
|
185
|
-
* refinements, {@link ArrayType | Array Types}, and
|
|
186
|
-
* {@link ObjectType | Object Types} preserve these laws when their contained
|
|
187
|
-
* Types do. A {@link union} additionally requires compatible dispatch: it
|
|
188
|
-
* encodes through the first member matching the Output and decodes through the
|
|
189
|
-
* first member accepting the Input. Member ordering is lawful only when those
|
|
190
|
-
* choices agree semantically. Encoded representations can overlap even when
|
|
191
|
-
* member Output types are disjoint.
|
|
192
|
-
*
|
|
193
|
-
* When encoding returns a refined value unchanged, the refinement can narrow
|
|
194
|
-
* `CanonicalInput` without changing its JavaScript representation. For example,
|
|
195
|
-
* {@link FiniteNumber} has `number` as its Input, while its Output and
|
|
196
|
-
* CanonicalInput are `FiniteNumber`: decoding can reject non-finite number
|
|
197
|
-
* candidates, and encoding only receives validated finite Outputs. A
|
|
198
|
-
* transformation can change the representation entirely. For
|
|
199
|
-
* {@link Int64FromInt64String}, Input is `string`, Output is `Int64`, and
|
|
200
|
-
* CanonicalInput is `Int64String`. Structural Type factories derive their
|
|
201
|
-
* CanonicalInput recursively from their contained Types.
|
|
202
|
-
*
|
|
203
|
-
* ### Why is to total?
|
|
204
|
-
*
|
|
205
|
-
* Suppose a Type accepts only strings containing decimal digits and decodes
|
|
206
|
-
* them to JavaScript numbers. Parsing `"42"` is possible, but the Type cannot
|
|
207
|
-
* lawfully declare its Output as `number`:
|
|
208
|
-
*
|
|
209
|
-
* ```text
|
|
210
|
-
* digits-only string ──partial decode──▶ number
|
|
211
|
-
* digits-only string ◀─── total encode ── number // impossible
|
|
212
|
-
* ```
|
|
213
|
-
*
|
|
214
|
-
* `number` also contains negative and fractional numbers, `NaN`, positive and
|
|
215
|
-
* negative infinity, and `-0`. None of those values has a digits-only
|
|
216
|
-
* representation, so `to` could not encode every valid Output.
|
|
10
|
+
* A runtime representation of a TypeScript type, including its encoded input,
|
|
11
|
+
* semantic output, structured errors, and canonical encoding.
|
|
217
12
|
*
|
|
218
|
-
*
|
|
13
|
+
* See the {@link @evolu/common!Type | Type overview}.
|
|
219
14
|
*
|
|
220
|
-
*
|
|
221
|
-
* digits-only string ──partial decode──▶ NonNegativeSafeInteger
|
|
222
|
-
* digits-only string ◀─── total encode ── NonNegativeSafeInteger
|
|
223
|
-
*
|
|
224
|
-
* "0042" ──decode──▶ 42 ──encode──▶ "42"
|
|
225
|
-
* ```
|
|
226
|
-
*
|
|
227
|
-
* Another lawful design keeps `number` as the Output but expands the Input
|
|
228
|
-
* representation to include a canonical string for every number, including
|
|
229
|
-
* `"NaN"`, `"Infinity"`, `"-Infinity"`, and `"-0"`, as well as negative and
|
|
230
|
-
* fractional numbers.
|
|
231
|
-
*
|
|
232
|
-
* The same principle applies when converting between two representations. Give
|
|
233
|
-
* each representation its own Type with the same exact Output. For example, a
|
|
234
|
-
* string representation and a number representation can both decode to the
|
|
235
|
-
* shared `SafeInteger` domain:
|
|
236
|
-
*
|
|
237
|
-
* ```text
|
|
238
|
-
* string ──partial decode──▶ SafeInteger
|
|
239
|
-
* string ◀─── total encode ── SafeInteger
|
|
240
|
-
*
|
|
241
|
-
* number ──partial decode──▶ SafeInteger
|
|
242
|
-
* number ◀─── total encode ── SafeInteger
|
|
243
|
-
* ```
|
|
244
|
-
*
|
|
245
|
-
* Conversion decodes the source representation, then total-encodes the shared
|
|
246
|
-
* Output into the target representation. If no lossless shared domain exists,
|
|
247
|
-
* the operation is a partial conversion, migration, or policy decision and
|
|
248
|
-
* should be an explicit function returning Result, not a Type transformation.
|
|
249
|
-
*
|
|
250
|
-
* ### Why can a typed operation throw?
|
|
251
|
-
*
|
|
252
|
-
* TypeScript proves structural assignability, but it cannot describe every
|
|
253
|
-
* runtime invariant. For example, it cannot express whether an object property
|
|
254
|
-
* is own, enumerable, or a data property. It also permits a wider object with
|
|
255
|
-
* excess properties where a narrower object type is expected.
|
|
256
|
-
*
|
|
257
|
-
* `fromUnknown` treats such invalid external values as expected data and
|
|
258
|
-
* returns a typed error. Typed boundaries instead assert the domain promised by
|
|
259
|
-
* their parameter type. If application code claims an accessor-backed object or
|
|
260
|
-
* an object with excess properties is an Object Output, the assertion throws
|
|
261
|
-
* because the application contract is broken. `orThrow` and `orNull` preserve
|
|
262
|
-
* the assertion at their typed `Input` boundary, then apply {@link getOrThrow}
|
|
263
|
-
* or {@link getOrNull} only to validation failures returned by the remaining
|
|
264
|
-
* pipeline.
|
|
265
|
-
*
|
|
266
|
-
* Consequently, structural representation errors such as sparse Arrays,
|
|
267
|
-
* accessors, and excess properties normally do not enter user-facing validation
|
|
268
|
-
* in typed application flows. They violate the producer's declared contract and
|
|
269
|
-
* throw as developer errors. At a genuinely unknown boundary, such as a
|
|
270
|
-
* schema-authoring tool, import, or external protocol, the same issues are
|
|
271
|
-
* legitimate typed validation errors and their formatter messages are useful.
|
|
272
|
-
*
|
|
273
|
-
* This distinction applies to data failures. Any Type operation, including
|
|
274
|
-
* `fromUnknown`, can throw when trusted Type-declaration code, such as a
|
|
275
|
-
* successful transformation callback, violates its declared contract.
|
|
276
|
-
*
|
|
277
|
-
* Materialize accessor values into plain data, remove properties the Type does
|
|
278
|
-
* not represent, or use a different Type. Silently discarding excess data would
|
|
279
|
-
* make the code constructing it dead while appearing to encode it successfully.
|
|
280
|
-
* One exact Object policy also keeps Output membership independent of parsing
|
|
281
|
-
* configuration. Exact structural policies also keep Output membership
|
|
282
|
-
* independent of whether a transformation happens to allocate a new value.
|
|
283
|
-
* Evolu Type therefore does not invoke accessors, discard excess properties, or
|
|
284
|
-
* make `to` fallible. This keeps `to` total for every legitimate Output and
|
|
285
|
-
* lets transformations compose without an encoding-error channel.
|
|
286
|
-
*
|
|
287
|
-
* ### How should values from another realm be handled?
|
|
288
|
-
*
|
|
289
|
-
* Code trust and data validation are separate decisions. Values returned by
|
|
290
|
-
* trusted legacy code or another realm can still be uncertain and should be
|
|
291
|
-
* validated. Realm-neutral Types accept an otherwise legitimate representation
|
|
292
|
-
* without requiring conversion merely because its built-ins belong to another
|
|
293
|
-
* realm.
|
|
294
|
-
*
|
|
295
|
-
* When an application trusts both the producer and its return contract, it can
|
|
296
|
-
* cast the boundary API's `unknown` because validation is redundant. Use a
|
|
297
|
-
* specialized Type or explicit transformation when the producer actually uses a
|
|
298
|
-
* different representation that needs adaptation or normalization.
|
|
299
|
-
*
|
|
300
|
-
* All executing JavaScript remains trusted. Deliberately forged built-ins,
|
|
301
|
-
* hostile Proxies, throwing traps, or sabotaged executable behavior can throw;
|
|
302
|
-
* Evolu Type does not selectively contain them or claim to be a security
|
|
303
|
-
* boundary for untrusted code.
|
|
304
|
-
*
|
|
305
|
-
* ### Why doesn't Evolu Type extract data from rich objects?
|
|
306
|
-
*
|
|
307
|
-
* Some validation libraries parse an object's data projection. An imaginary
|
|
308
|
-
* validation library can enumerate own enumerable string properties and decode
|
|
309
|
-
* them into a fresh plain object. That lets a class instance decode as plain
|
|
310
|
-
* data while its prototype and methods are ignored. The same general policy can
|
|
311
|
-
* treat a `Date` or `Map` as an empty Record and can invoke enumerable getters.
|
|
312
|
-
* This is a coherent but intentionally forgiving normalization model.
|
|
313
|
-
*
|
|
314
|
-
* Evolu Type validates exactly the runtime representation defined by each Type;
|
|
315
|
-
* it does not implicitly project one representation into another. The
|
|
316
|
-
* predefined {@link Object} defines an open plain-object representation with
|
|
317
|
-
* unknown values, {@link object} defines a closed plain-object representation,
|
|
318
|
-
* and {@link record} defines a plain-dictionary representation whose complete
|
|
319
|
-
* set of own properties are its entries. Their realm-neutral plain-object rule
|
|
320
|
-
* accepts a `null` prototype or an immediate root prototype whose own prototype
|
|
321
|
-
* is `null`; ordinary class instances and deeper prototype chains are rejected.
|
|
322
|
-
* Every property must be an enumerable data property; inherited members are not
|
|
323
|
-
* entries, while accessors and hidden properties are invalid instead of being
|
|
324
|
-
* invoked or ignored. {@link array} similarly defines a dense sequence whose
|
|
325
|
-
* only own properties are `length` and its indexed data properties;
|
|
326
|
-
* {@link tuple} applies the same representation rules with a fixed length and a
|
|
327
|
-
* distinct Type for each position. Only an explicit {@link transform} changes
|
|
328
|
-
* the representation. Consequently, `is` tests exact Output membership and `to`
|
|
329
|
-
* stays total for valid Outputs.
|
|
330
|
-
*
|
|
331
|
-
* ### Why is JsonValue stricter than JSON.stringify?
|
|
332
|
-
*
|
|
333
|
-
* `JSON.stringify` is a forgiving data projection. It can invoke `toJSON` and
|
|
334
|
-
* accessors, discard object properties, replace unsupported array elements and
|
|
335
|
-
* non-finite numbers with `null`, and normalize `-0` to `0`. Those rules are
|
|
336
|
-
* useful for ordinary serialization, but they do not preserve an exact value.
|
|
337
|
-
*
|
|
338
|
-
* {@link JsonValue} instead defines data that is already represented as data.
|
|
339
|
-
* Invalid runtime behavior and values are rejected rather than interpreted or
|
|
340
|
-
* silently discarded. Its encoder is total and stack-safe for every valid
|
|
341
|
-
* Output, and {@link JsonValueFromJson} preserves the semantic value when it is
|
|
342
|
-
* encoded and decoded, including JavaScript's distinction between `-0` and `0`.
|
|
343
|
-
* Use an explicit transformation before this boundary when a projection or
|
|
344
|
-
* other normalization is desired.
|
|
345
|
-
*
|
|
346
|
-
* ### Why are Types pure and synchronous?
|
|
347
|
-
*
|
|
348
|
-
* A Type describes data meaning, not work. Time, I/O, dependencies, external
|
|
349
|
-
* state, authorization, and other contextual decisions belong in a {@link Task}.
|
|
350
|
-
* Use a Type to decode the data required by that work, then pass the decoded
|
|
351
|
-
* value to a Task. A pure synchronous conversion that can fail can be an
|
|
352
|
-
* ordinary function returning Result.
|
|
353
|
-
*
|
|
354
|
-
* Keeping those responsibilities separate prevents an Evolu Type from becoming
|
|
355
|
-
* a hidden application workflow. It also keeps validation deterministic,
|
|
356
|
-
* dependency-free, immediately composable, and straightforward to test.
|
|
357
|
-
*
|
|
358
|
-
* ### What if only decoding is needed?
|
|
359
|
-
*
|
|
360
|
-
* Use `fromUnknown` for unknown data. For typed application data, call `from`
|
|
361
|
-
* at the boundary its input type proves, or use `orThrow` or `orNull` for a
|
|
362
|
-
* flat conversion from `Input`. The canonical `to` encoder still keeps the Type
|
|
363
|
-
* lawful and composable with transformations and structural Types. A genuinely
|
|
364
|
-
* irreversible operation is a separate function or Task, not a Type
|
|
365
|
-
* transformation.
|
|
366
|
-
*
|
|
367
|
-
* @group Core Types
|
|
15
|
+
* @group Core
|
|
368
16
|
*/
|
|
369
17
|
export interface Type<Name extends TypeName, in out Input, in out Output, Error extends TypeError, in out Parent extends TypeNode | null = null, in out Errors extends TypeError = Error | ([Parent] extends [infer P extends TypeNode] ? InferErrors<P> : never), in out CustomFrom extends CustomFromOperation = never, in out CanonicalInput extends Input = Input, in out IdentityEncoding extends boolean = true> extends TypeNode {
|
|
370
18
|
/** The name identifying this Type node. */
|
|
@@ -423,7 +71,20 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
423
71
|
readonly [identityEncodingSymbol]: IdentityEncoding;
|
|
424
72
|
/** The one preceding Type node, or `null` for a root Type. */
|
|
425
73
|
readonly parent: Parent;
|
|
426
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Decodes an unknown value through the complete Type pipeline.
|
|
76
|
+
*
|
|
77
|
+
* ### Example
|
|
78
|
+
*
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { PositiveInt } from "@evolu/common";
|
|
81
|
+
*
|
|
82
|
+
* const value: unknown = 42;
|
|
83
|
+
* const result = PositiveInt.fromUnknown(value);
|
|
84
|
+
*
|
|
85
|
+
* expectOk(result, 42);
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
427
88
|
readonly fromUnknown: (value: unknown, options?: ValidationOptions) => Result<Output, Errors>;
|
|
428
89
|
/**
|
|
429
90
|
* Formats an error returned by `fromUnknown` or `from` as one human-readable
|
|
@@ -433,6 +94,19 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
433
94
|
* Structural errors retain nested errors and their locations in the typed
|
|
434
95
|
* error value. This formatter does not encode paths or enumerate nested
|
|
435
96
|
* errors in its message.
|
|
97
|
+
*
|
|
98
|
+
* ### Example
|
|
99
|
+
*
|
|
100
|
+
* ```ts
|
|
101
|
+
* import { String } from "@evolu/common";
|
|
102
|
+
*
|
|
103
|
+
* const result = String.fromUnknown(42);
|
|
104
|
+
*
|
|
105
|
+
* expectErr(result, { type: "TypeOf", expected: "String", value: 42 });
|
|
106
|
+
* expect(String.formatError(result.error)).toBe(
|
|
107
|
+
* "A value 42 is not a string.",
|
|
108
|
+
* );
|
|
109
|
+
* ```
|
|
436
110
|
*/
|
|
437
111
|
readonly formatError: TypeErrorFormatter<Errors>;
|
|
438
112
|
/**
|
|
@@ -468,6 +142,52 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
468
142
|
* developer error. The Error message identifies the expected boundary Type,
|
|
469
143
|
* and its cause preserves the structured validation error. Only failures
|
|
470
144
|
* introduced after that boundary are returned through `Result`.
|
|
145
|
+
*
|
|
146
|
+
* ### Example
|
|
147
|
+
*
|
|
148
|
+
* A form already guarantees every constraint on a title, while a new note
|
|
149
|
+
* input guarantees only trimmed text. The note's parent boundary validates
|
|
150
|
+
* only the constraints that the form does not guarantee:
|
|
151
|
+
*
|
|
152
|
+
* ```ts
|
|
153
|
+
* import {
|
|
154
|
+
* flatMapResult,
|
|
155
|
+
* NonEmptyTrimmedString100,
|
|
156
|
+
* object,
|
|
157
|
+
* TrimmedString,
|
|
158
|
+
* type MaxLengthError,
|
|
159
|
+
* type MinLengthError,
|
|
160
|
+
* type Result,
|
|
161
|
+
* } from "@evolu/common";
|
|
162
|
+
*
|
|
163
|
+
* const Todo = object({
|
|
164
|
+
* title: NonEmptyTrimmedString100,
|
|
165
|
+
* note: NonEmptyTrimmedString100,
|
|
166
|
+
* });
|
|
167
|
+
*
|
|
168
|
+
* const saveTodo = (
|
|
169
|
+
* title: NonEmptyTrimmedString100,
|
|
170
|
+
* note: TrimmedString,
|
|
171
|
+
* ) => {
|
|
172
|
+
* // @ts-expect-error TrimmedString does not guarantee a non-empty value
|
|
173
|
+
* // with at most 100 characters.
|
|
174
|
+
* Todo.from({ title, note });
|
|
175
|
+
*
|
|
176
|
+
* return flatMapResult(
|
|
177
|
+
* Todo.props.note.from.parent.parent(note),
|
|
178
|
+
* (note) => Todo.from({ title, note }),
|
|
179
|
+
* );
|
|
180
|
+
* };
|
|
181
|
+
*
|
|
182
|
+
* const title = NonEmptyTrimmedString100.orThrow("Buy milk");
|
|
183
|
+
* const note = TrimmedString.orThrow("Remember oat milk");
|
|
184
|
+
* const result = saveTodo(title, note);
|
|
185
|
+
*
|
|
186
|
+
* expectTypeOf(result).toEqualTypeOf<
|
|
187
|
+
* Result<typeof Todo.Output, MaxLengthError<100> | MinLengthError<1>>
|
|
188
|
+
* >();
|
|
189
|
+
* expectOk(result, { title, note });
|
|
190
|
+
* ```
|
|
471
191
|
*/
|
|
472
192
|
readonly from: [CustomFrom] extends [never] ? [Parent] extends [infer P extends TypeNode] ? FromOperation<Output, Error, P> : TypeOperationFn<"from", Output, Output, never> : CustomFrom;
|
|
473
193
|
/**
|
|
@@ -477,6 +197,16 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
477
197
|
* `to` runs the complete encoding pipeline. Its first `.parent` stops at the
|
|
478
198
|
* immediate parent Output, and each additional suffix stops one Type closer
|
|
479
199
|
* to the root. Every entry point accepts this Type's `Output`.
|
|
200
|
+
*
|
|
201
|
+
* ### Example
|
|
202
|
+
*
|
|
203
|
+
* ```ts
|
|
204
|
+
* import { Int64, Int64FromInt64String } from "@evolu/common";
|
|
205
|
+
*
|
|
206
|
+
* const value = Int64.orThrow(42n);
|
|
207
|
+
*
|
|
208
|
+
* expect(Int64FromInt64String.to(value)).toBe("42");
|
|
209
|
+
* ```
|
|
480
210
|
*/
|
|
481
211
|
readonly to: [Parent] extends [infer P extends TypeNode] ? ToOperation<Output, CanonicalInput, P> : (value: Output) => CanonicalInput;
|
|
482
212
|
/**
|
|
@@ -506,6 +236,9 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
506
236
|
*
|
|
507
237
|
* // Equivalent because `from.parent` is this Type's deepest `from` operation:
|
|
508
238
|
* const sameValue = getOrThrow(NonEmptyString.from.parent("Evolu"));
|
|
239
|
+
*
|
|
240
|
+
* expect(value).toBe("Evolu");
|
|
241
|
+
* expect(sameValue).toBe(value);
|
|
509
242
|
* ```
|
|
510
243
|
*/
|
|
511
244
|
readonly orThrow: TypeOperationFn<"orThrow", Input, Output, never>;
|
|
@@ -536,11 +269,19 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
536
269
|
*
|
|
537
270
|
* // Equivalent because `from.parent` is this Type's deepest `from` operation:
|
|
538
271
|
* const sameValue = getOrNull(NonEmptyString.from.parent("Evolu"));
|
|
272
|
+
*
|
|
273
|
+
* expect(value).toBe("Evolu");
|
|
274
|
+
* expect(sameValue).toBe(value);
|
|
275
|
+
* expect(NonEmptyString.orNull("")).toBeNull();
|
|
539
276
|
* ```
|
|
540
277
|
*/
|
|
541
278
|
readonly orNull: TypeOperationFn<"orNull", Input, Output, never>;
|
|
542
279
|
}
|
|
543
|
-
/**
|
|
280
|
+
/**
|
|
281
|
+
* A capitalized name identifying a {@link Type} node.
|
|
282
|
+
*
|
|
283
|
+
* @group Core
|
|
284
|
+
*/
|
|
544
285
|
export type TypeName = Capitalize<string>;
|
|
545
286
|
/**
|
|
546
287
|
* A plain structured error produced by a {@link Type} operation.
|
|
@@ -552,7 +293,7 @@ export type TypeName = Capitalize<string>;
|
|
|
552
293
|
* only when it intentionally represents the same error contract. Accidental
|
|
553
294
|
* reuse prevents reliable discriminated-union narrowing.
|
|
554
295
|
*
|
|
555
|
-
* @group Core
|
|
296
|
+
* @group Core
|
|
556
297
|
*/
|
|
557
298
|
export interface TypeError<Name extends TypeName = TypeName> {
|
|
558
299
|
readonly type: Name;
|
|
@@ -567,7 +308,7 @@ interface TransparentTypeError {
|
|
|
567
308
|
* Structural errors such as Array and Union errors extend {@link TypeError}
|
|
568
309
|
* instead because they locate nested errors rather than own one value.
|
|
569
310
|
*
|
|
570
|
-
* @group Core
|
|
311
|
+
* @group Core
|
|
571
312
|
*/
|
|
572
313
|
export interface TypeValueError<Name extends TypeName = TypeName> extends TypeError<Name> {
|
|
573
314
|
readonly value: unknown;
|
|
@@ -575,10 +316,15 @@ export interface TypeValueError<Name extends TypeName = TypeName> extends TypeEr
|
|
|
575
316
|
/**
|
|
576
317
|
* Formats a structured {@link TypeError} as a human-readable message.
|
|
577
318
|
*
|
|
578
|
-
* @group Core
|
|
319
|
+
* @group Core
|
|
579
320
|
*/
|
|
580
321
|
export type TypeErrorFormatter<Error extends TypeError> = (error: Error) => string;
|
|
581
|
-
/**
|
|
322
|
+
/**
|
|
323
|
+
* The common structural shape of every {@link Type}, with its specific type
|
|
324
|
+
* parameters erased.
|
|
325
|
+
*
|
|
326
|
+
* @group Core
|
|
327
|
+
*/
|
|
582
328
|
export interface TypeNode {
|
|
583
329
|
readonly name: TypeName;
|
|
584
330
|
readonly "~standard": StandardSchemaV1.Props<unknown, unknown>;
|
|
@@ -601,7 +347,7 @@ export interface TypeNode {
|
|
|
601
347
|
* Asserts that a value belongs to a {@link Type} Output domain.
|
|
602
348
|
*
|
|
603
349
|
* Use this for internal invariants, not external input. Validate external input
|
|
604
|
-
* with `Type.fromUnknown` so
|
|
350
|
+
* with `Type.fromUnknown` so validation failures remain typed values. A failed
|
|
605
351
|
* assertion uses the Type name for its message and preserves the exact Output
|
|
606
352
|
* validation error as the thrown Error's cause.
|
|
607
353
|
*
|
|
@@ -621,38 +367,36 @@ export interface TypeNode {
|
|
|
621
367
|
* >();
|
|
622
368
|
* ```
|
|
623
369
|
*
|
|
624
|
-
* @group Core
|
|
370
|
+
* @group Core
|
|
625
371
|
*/
|
|
626
372
|
export declare const assertType: <T extends TypeNode>(type: T, value: unknown) => asserts value is T["Output"];
|
|
627
373
|
/**
|
|
628
|
-
*
|
|
374
|
+
* Creates localized copies of selected {@link Type} declarations.
|
|
629
375
|
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
* Lazy error interfaces.
|
|
376
|
+
* Pass the Types used together in one localization scope and formatter maps
|
|
377
|
+
* keyed by locale. TypeScript infers every formatter required by the selected
|
|
378
|
+
* Types, including errors from nested structural Types and recursive Lazy
|
|
379
|
+
* Types. Every locale must provide the complete inferred formatter set;
|
|
380
|
+
* missing and unrelated formatters are compile-time errors.
|
|
636
381
|
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
382
|
+
* The result preserves the locale names, selected Type names, and exact
|
|
383
|
+
* TypeScript types. A localized Type validates exactly like its source Type;
|
|
384
|
+
* only its human-readable `formatError` and Standard Schema messages change.
|
|
385
|
+
* The source Types remain unchanged.
|
|
640
386
|
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
387
|
+
* Parents and reflected child Types are localized with the same formatter set.
|
|
388
|
+
* Structural Types retain error paths and delegate nested messages to the Type
|
|
389
|
+
* that produced them. Different localized Type sets can coexist in separate
|
|
390
|
+
* application or dependency-injection scopes.
|
|
643
391
|
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
*
|
|
392
|
+
* Localization is scoped to the selected Types instead of a package-wide
|
|
393
|
+
* translation registry. Static imports give bundlers an explicit dependency
|
|
394
|
+
* graph, so unrelated Types, locales, and formatters can be removed. Bundling
|
|
395
|
+
* every locale an app supports also allows language changes without a network
|
|
396
|
+
* connection.
|
|
648
397
|
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
* dependency graph from those Types to their formatters, so unrelated Type and
|
|
652
|
-
* localization code can be removed. An app supplies all locales it supports in
|
|
653
|
-
* the same self-contained bundle, allowing users to change language without a
|
|
654
|
-
* network connection. Different localized Type sets can coexist on one page or
|
|
655
|
-
* in separate dependency-injection scopes.
|
|
398
|
+
* The selected Type map, locale map, and formatter maps must be plain objects
|
|
399
|
+
* with own enumerable string-keyed data properties.
|
|
656
400
|
*
|
|
657
401
|
* ### Example
|
|
658
402
|
*
|
|
@@ -662,7 +406,7 @@ export declare const assertType: <T extends TypeNode>(type: T, value: unknown) =
|
|
|
662
406
|
*
|
|
663
407
|
* const Label = minLength(1)(String);
|
|
664
408
|
*
|
|
665
|
-
* const
|
|
409
|
+
* const typesByLocale = localizeTypes(
|
|
666
410
|
* { Label },
|
|
667
411
|
* {
|
|
668
412
|
* cs: {
|
|
@@ -672,11 +416,66 @@ export declare const assertType: <T extends TypeNode>(type: T, value: unknown) =
|
|
|
672
416
|
* },
|
|
673
417
|
* );
|
|
674
418
|
*
|
|
675
|
-
* expectTypeOf<typeof
|
|
419
|
+
* expectTypeOf<typeof typesByLocale.cs.Label>().toEqualTypeOf<
|
|
676
420
|
* typeof Label
|
|
677
421
|
* >();
|
|
422
|
+
*
|
|
423
|
+
* const result = typesByLocale.cs.Label.fromUnknown("");
|
|
424
|
+
* expectErr(result, { type: "MinLength1", min: 1, value: "" });
|
|
425
|
+
* expect(typesByLocale.cs.Label.formatError(result.error)).toBe(
|
|
426
|
+
* "Text nesmí být prázdný.",
|
|
427
|
+
* );
|
|
678
428
|
* ```
|
|
679
429
|
*
|
|
430
|
+
* ### Supported locales
|
|
431
|
+
*
|
|
432
|
+
* English is built in; use {@link Type} directly for its default formatters.
|
|
433
|
+
* The following additional locales are available:
|
|
434
|
+
*
|
|
435
|
+
* - Arabic (`ar`)
|
|
436
|
+
* - Bengali (`bn`)
|
|
437
|
+
* - Catalan (`ca`)
|
|
438
|
+
* - Chinese, Simplified (`zhCN`)
|
|
439
|
+
* - Chinese, Traditional (`zhTW`)
|
|
440
|
+
* - Croatian (`hr`)
|
|
441
|
+
* - Czech (`cs`)
|
|
442
|
+
* - Danish (`da`)
|
|
443
|
+
* - Dutch (`nl`)
|
|
444
|
+
* - Filipino (`fil`)
|
|
445
|
+
* - Finnish (`fi`)
|
|
446
|
+
* - French (`fr`)
|
|
447
|
+
* - German (`de`)
|
|
448
|
+
* - Greek (`el`)
|
|
449
|
+
* - Hebrew (`he`)
|
|
450
|
+
* - Hindi (`hi`)
|
|
451
|
+
* - Hungarian (`hu`)
|
|
452
|
+
* - Indonesian (`id`)
|
|
453
|
+
* - Italian (`it`)
|
|
454
|
+
* - Japanese (`ja`)
|
|
455
|
+
* - Korean (`ko`)
|
|
456
|
+
* - Malay (`ms`)
|
|
457
|
+
* - Malayalam (`ml`)
|
|
458
|
+
* - Marathi (`mr`)
|
|
459
|
+
* - Norwegian Bokmål (`nb`)
|
|
460
|
+
* - Persian (`fa`)
|
|
461
|
+
* - Polish (`pl`)
|
|
462
|
+
* - Portuguese (`pt`)
|
|
463
|
+
* - Portuguese, Brazilian (`ptBR`)
|
|
464
|
+
* - Punjabi (`pa`)
|
|
465
|
+
* - Romanian (`ro`)
|
|
466
|
+
* - Slovak (`sk`)
|
|
467
|
+
* - Slovenian (`sl`)
|
|
468
|
+
* - Spanish (`es`)
|
|
469
|
+
* - Swahili (`sw`)
|
|
470
|
+
* - Swedish (`sv`)
|
|
471
|
+
* - Tamil (`ta`)
|
|
472
|
+
* - Telugu (`te`)
|
|
473
|
+
* - Thai (`th`)
|
|
474
|
+
* - Turkish (`tr`)
|
|
475
|
+
* - Ukrainian (`uk`)
|
|
476
|
+
* - Urdu (`ur`)
|
|
477
|
+
* - Vietnamese (`vi`)
|
|
478
|
+
*
|
|
680
479
|
* @group Localization
|
|
681
480
|
*/
|
|
682
481
|
export declare const localizeTypes: LocalizeTypes;
|
|
@@ -762,15 +561,20 @@ declare const identityEncodingSymbol: unique symbol;
|
|
|
762
561
|
* age: optional(PositiveInt),
|
|
763
562
|
* });
|
|
764
563
|
* interface User extends InferType<typeof User> {}
|
|
564
|
+
*
|
|
565
|
+
* const user = User.orThrow({ name: "Ada", age: 37 });
|
|
566
|
+
*
|
|
567
|
+
* expectTypeOf(user).toExtend<User>();
|
|
568
|
+
* expect(user.name).toBe("Ada");
|
|
765
569
|
* ```
|
|
766
570
|
*
|
|
767
|
-
* @group
|
|
571
|
+
* @group Core
|
|
768
572
|
*/
|
|
769
573
|
export type InferType<T extends TypeNode> = T["Output"];
|
|
770
574
|
/**
|
|
771
575
|
* The union of errors a {@link Type} can return from `fromUnknown`.
|
|
772
576
|
*
|
|
773
|
-
* @group
|
|
577
|
+
* @group Core
|
|
774
578
|
*/
|
|
775
579
|
export type InferErrors<T extends TypeNode> = T[typeof errorsSymbol];
|
|
776
580
|
type CanonicalInputOf<T extends TypeNode> = T extends TypeNode ? T["CanonicalInput"] : never;
|
|
@@ -842,7 +646,7 @@ type TypeOperationFn<Kind extends "from" | "orThrow" | "orNull", Input, Output,
|
|
|
842
646
|
/**
|
|
843
647
|
* Configures how container {@link Type} operations report errors.
|
|
844
648
|
*
|
|
845
|
-
* @group Core
|
|
649
|
+
* @group Core
|
|
846
650
|
*/
|
|
847
651
|
export interface ValidationOptions {
|
|
848
652
|
/** Controls whether container {@link Type} operations return one or all errors. */
|
|
@@ -914,10 +718,12 @@ type ConcreteChildTypeNameError = CompileTimeError<"Type", "Name must be one con
|
|
|
914
718
|
* expectErr(Text.fromUnknown(42), { type: "Text", value: 42 });
|
|
915
719
|
* ```
|
|
916
720
|
*
|
|
917
|
-
* @group
|
|
721
|
+
* @group Construction
|
|
918
722
|
*/
|
|
919
723
|
export declare function createType<Name extends TypeName, Output, Error extends TypeError>(name: ValidateConcreteTypeName<Name>, fromUnknown: (value: unknown) => Result<Output, Error>, formatError: TypeErrorFormatter<NoInfer<Error>>): Type<Name, Output, Output, Error, null, Error, never, Output>;
|
|
724
|
+
/** Creates an infallible child Type that preserves its parent's Output. */
|
|
920
725
|
export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode>(name: ValidateConcreteTypeName<Name>, parent: ValidateParent<ParentType>, fromParent: (value: ParentType["Output"]) => Result<ParentType["Output"], never>): Type<Name, ParentType["Input"], ParentType["Output"], never, ParentType, InferErrors<ParentType>, ChildCustomFrom<ParentType, ParentType["Output"], never>, CanonicalInputForChild<ParentType, ParentType["Output"]>, IdentityEncodingOf<ParentType>>;
|
|
726
|
+
/** Creates a fallible child Type that narrows its parent's Output. */
|
|
921
727
|
export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode, Output extends ParentType["Output"], Error extends TypeError<Name>>(name: Name, parent: ValidateBrandParent<Name, ParentType>, fromParent: (value: ParentType["Output"]) => Result<Output, Error>, formatError: [Error] extends [never] ? never : TypeErrorFormatter<NoInfer<Error>>): Type<Name, ParentType["Input"], Output, Error, ParentType, Error | InferErrors<ParentType>, ChildCustomFrom<ParentType, Output, Error>, CanonicalInputForChild<ParentType, Output>, IdentityEncodingOf<ParentType>>;
|
|
922
728
|
/**
|
|
923
729
|
* Transform {@link Type}.
|
|
@@ -925,12 +731,19 @@ export declare function createType<Name extends TypeName, ParentType extends Con
|
|
|
925
731
|
* `from` accepts the semantic Output. `from.parent` converts the parent Output
|
|
926
732
|
* to the output Type Input, then runs the complete output Type pipeline. `to`
|
|
927
733
|
* canonically encodes every output Type value before converting it back through
|
|
928
|
-
* the parent Type.
|
|
929
|
-
*
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
933
|
-
*
|
|
734
|
+
* the parent Type.
|
|
735
|
+
*
|
|
736
|
+
* The callbacks must form a lawful codec: decoding `to(output)` must reproduce
|
|
737
|
+
* the same semantic Output for every valid output value. Encoding may
|
|
738
|
+
* canonicalize multiple parent representations, but it must be total and must
|
|
739
|
+
* not lose distinctions present in the Output domain.
|
|
740
|
+
*
|
|
741
|
+
* Transformation callbacks are Type construction code. Their successful
|
|
742
|
+
* results are asserted against the declared boundary so a broken callback fails
|
|
743
|
+
* as a developer error rather than becoming a validation error. Like all
|
|
744
|
+
* Type-construction callbacks, they are trusted to follow their declared
|
|
745
|
+
* TypeScript types. A `Result<_, never>` callback is therefore trusted never to
|
|
746
|
+
* return an `Err`.
|
|
934
747
|
*
|
|
935
748
|
* Errors from the parent and the forward callback remain unchanged. A forward
|
|
936
749
|
* callback error must use the transformation name as its type. Errors from the
|
|
@@ -943,23 +756,36 @@ export declare function createType<Name extends TypeName, ParentType extends Con
|
|
|
943
756
|
* ### Example
|
|
944
757
|
*
|
|
945
758
|
* ```ts
|
|
946
|
-
* import {
|
|
759
|
+
* import {
|
|
760
|
+
* Boolean,
|
|
761
|
+
* literal,
|
|
762
|
+
* ok,
|
|
763
|
+
* transform,
|
|
764
|
+
* union,
|
|
765
|
+
* } from "@evolu/common";
|
|
947
766
|
*
|
|
948
|
-
* const
|
|
949
|
-
*
|
|
950
|
-
*
|
|
951
|
-
*
|
|
767
|
+
* const BooleanString = union(literal("false"), literal("true"));
|
|
768
|
+
* const BooleanFromString = transform(
|
|
769
|
+
* "BooleanFromString",
|
|
770
|
+
* BooleanString,
|
|
771
|
+
* Boolean,
|
|
772
|
+
* {
|
|
773
|
+
* from: (value) => ok(value === "true"),
|
|
774
|
+
* to: (value) => (value ? "true" : "false"),
|
|
775
|
+
* },
|
|
776
|
+
* );
|
|
952
777
|
*
|
|
953
|
-
* expectOk(
|
|
954
|
-
*
|
|
778
|
+
* expectOk(BooleanFromString.from.parent("true"), true);
|
|
779
|
+
* expect(BooleanFromString.to(false)).toBe("false");
|
|
955
780
|
* ```
|
|
956
781
|
*
|
|
957
|
-
* @group
|
|
782
|
+
* @group Construction
|
|
958
783
|
*/
|
|
959
784
|
export declare function transform<Name extends TypeName, ParentType extends ConcreteTypeNode, OutputType extends ConcreteTypeNode, ToOutput extends ParentType["Output"]>(name: ValidateChildTypeName<Name, ParentType>, parent: ValidateParent<ParentType>, output: ValidateOutput<OutputType>, operations: {
|
|
960
785
|
readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], never>;
|
|
961
786
|
readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
|
|
962
787
|
}): TransformType<ParentType, OutputType, Name, never, ToOutput>;
|
|
788
|
+
/** Creates a fallible transformed Type with its own error formatter. */
|
|
963
789
|
export declare function transform<Name extends TypeName, ParentType extends ConcreteTypeNode, OutputType extends ConcreteTypeNode, ToOutput extends ParentType["Output"], FromError extends {
|
|
964
790
|
readonly type: Name;
|
|
965
791
|
readonly outputError?: never;
|
|
@@ -967,17 +793,26 @@ export declare function transform<Name extends TypeName, ParentType extends Conc
|
|
|
967
793
|
readonly from: (value: ParentType["Output"]) => Result<OutputType["Input"], FromError>;
|
|
968
794
|
readonly to: (value: CanonicalInputOf<OutputType>) => ToOutput;
|
|
969
795
|
}, formatError: [FromError] extends [never] ? never : TypeErrorFormatter<NoInfer<FromError>>): TransformType<ParentType, OutputType, Name, FromError, ToOutput>;
|
|
970
|
-
/**
|
|
796
|
+
/**
|
|
797
|
+
* The {@link Type} returned by {@link transform}.
|
|
798
|
+
*
|
|
799
|
+
* @group Construction
|
|
800
|
+
*/
|
|
971
801
|
export interface TransformType<ParentType extends TypeNode, OutputType extends TypeNode, Name extends TypeName, FromError extends TypeError<Name>, ToOutput extends ParentType["Output"] = ParentType["Output"]> extends Type<Name, ParentType["Input"], OutputType["Output"], TransformError<Name, FromError, TypeFromError<OutputType>>, ParentType, TransformError<Name, FromError, TypeFromError<OutputType>> | InferErrors<ParentType>, ChildCustomFrom<ParentType, OutputType["Output"], TransformError<Name, FromError, TypeFromError<OutputType>>>, CanonicalInputForChild<ParentType, ToOutput>, false> {
|
|
972
802
|
readonly [reflectedTypesSymbol]?: OutputType;
|
|
973
803
|
readonly output: OutputType;
|
|
974
804
|
}
|
|
975
|
-
/**
|
|
805
|
+
/**
|
|
806
|
+
* An error produced by {@link transform} while decoding or validating its
|
|
807
|
+
* output.
|
|
808
|
+
*
|
|
809
|
+
* @group Construction
|
|
810
|
+
*/
|
|
976
811
|
export type TransformError<Name extends TypeName, OwnError extends TypeError<Name>, OutputError extends TypeError> = OwnError | ([OutputError] extends [never] ? never : TransformOutputError<Name, OutputError>);
|
|
977
812
|
/**
|
|
978
813
|
* Wraps an error produced by the output {@link Type} of {@link transform}.
|
|
979
814
|
*
|
|
980
|
-
* @group
|
|
815
|
+
* @group Construction
|
|
981
816
|
*/
|
|
982
817
|
export interface TransformOutputError<Name extends TypeName, OutputError extends TypeError> extends TypeError<Name>, TransparentTypeError {
|
|
983
818
|
/** The error returned by the output Type. */
|
|
@@ -990,10 +825,23 @@ type DeepestFromError<Operation> = DeepestFromOperation<Operation> extends (...a
|
|
|
990
825
|
type TypeFromError<T extends TypeNode> = unknown extends T[typeof customFromSymbol] ? DeepestFromError<TypeFromOperation<T>> : [T[typeof customFromSymbol]] extends [never] ? NonRootErrors<T> : DeepestFromError<T[typeof customFromSymbol]>;
|
|
991
826
|
declare const templateLiteralSyntaxSymbolType: unique symbol;
|
|
992
827
|
declare const templateLiteralSyntaxSymbol: typeof templateLiteralSyntaxSymbolType;
|
|
993
|
-
/**
|
|
828
|
+
/**
|
|
829
|
+
* An infallible {@link Type} accepting every value.
|
|
830
|
+
*
|
|
831
|
+
* @group Base
|
|
832
|
+
*/
|
|
994
833
|
export declare const Unknown: Type<"Unknown", unknown, unknown, never, null, never, never, unknown, true>;
|
|
995
|
-
/**
|
|
834
|
+
/**
|
|
835
|
+
* A {@link Type} rejecting every value.
|
|
836
|
+
*
|
|
837
|
+
* @group Base
|
|
838
|
+
*/
|
|
996
839
|
export declare const Never: Type<"Never", never, never, NeverError, null, NeverError, never, never, true>;
|
|
840
|
+
/**
|
|
841
|
+
* Error returned by {@link Never} for every value.
|
|
842
|
+
*
|
|
843
|
+
* @group Base
|
|
844
|
+
*/
|
|
997
845
|
export interface NeverError extends TypeError<"Never"> {
|
|
998
846
|
readonly value: unknown;
|
|
999
847
|
}
|
|
@@ -1005,7 +853,11 @@ interface TypeOfOutputByName {
|
|
|
1005
853
|
readonly Symbol: symbol;
|
|
1006
854
|
readonly Function: globalThis.Function;
|
|
1007
855
|
}
|
|
1008
|
-
/**
|
|
856
|
+
/**
|
|
857
|
+
* Error returned when `typeof` does not match the expected JavaScript type.
|
|
858
|
+
*
|
|
859
|
+
* @group Base
|
|
860
|
+
*/
|
|
1009
861
|
export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends TypeError<"TypeOf"> {
|
|
1010
862
|
readonly expected: Name;
|
|
1011
863
|
readonly value: unknown;
|
|
@@ -1033,6 +885,8 @@ export interface TypeOfError<Name extends keyof TypeOfOutputByName> extends Type
|
|
|
1033
885
|
* expectTypeOf<WireValue100>().toEqualTypeOf<
|
|
1034
886
|
* string & Brand<"MaxLength100">
|
|
1035
887
|
* >();
|
|
888
|
+
* expectOk(WireValue100.fromUnknown(""), "");
|
|
889
|
+
* expectOk(WireValue100.fromUnknown(" value "), " value ");
|
|
1036
890
|
* ```
|
|
1037
891
|
*
|
|
1038
892
|
* @group String
|
|
@@ -1107,21 +961,37 @@ export declare const String: Type<"String", string, string, TypeOfError<"String"
|
|
|
1107
961
|
* @group Number
|
|
1108
962
|
*/
|
|
1109
963
|
export declare const Number: Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>;
|
|
1110
|
-
/**
|
|
964
|
+
/**
|
|
965
|
+
* A JavaScript bigint {@link Type}.
|
|
966
|
+
*
|
|
967
|
+
* @group Base
|
|
968
|
+
*/
|
|
1111
969
|
export declare const BigInt: Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>;
|
|
1112
|
-
/**
|
|
970
|
+
/**
|
|
971
|
+
* A JavaScript boolean {@link Type}.
|
|
972
|
+
*
|
|
973
|
+
* @group Base
|
|
974
|
+
*/
|
|
1113
975
|
export declare const Boolean: Type<"Boolean", boolean, boolean, TypeOfError<"Boolean">, null, TypeOfError<"Boolean">, never, boolean, true>;
|
|
1114
|
-
/**
|
|
976
|
+
/**
|
|
977
|
+
* A JavaScript symbol {@link Type}.
|
|
978
|
+
*
|
|
979
|
+
* @group Base
|
|
980
|
+
*/
|
|
1115
981
|
export declare const Symbol: Type<"Symbol", symbol, symbol, TypeOfError<"Symbol">, null, TypeOfError<"Symbol">, never, symbol, true>;
|
|
1116
|
-
/**
|
|
982
|
+
/**
|
|
983
|
+
* A JavaScript function {@link Type}.
|
|
984
|
+
*
|
|
985
|
+
* @group Base
|
|
986
|
+
*/
|
|
1117
987
|
export declare const Function: Type<"Function", Function, Function, TypeOfError<"Function">, null, TypeOfError<"Function">, never, Function, true>;
|
|
1118
988
|
/**
|
|
1119
|
-
*
|
|
989
|
+
* A {@link Type} validating Evolu Type declarations.
|
|
1120
990
|
*
|
|
1121
991
|
* This is useful when a Type itself crosses an unknown boundary or must be
|
|
1122
992
|
* asserted with {@link assertType}.
|
|
1123
993
|
*
|
|
1124
|
-
* @group Core
|
|
994
|
+
* @group Core
|
|
1125
995
|
*/
|
|
1126
996
|
export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeError, null, EvoluTypeError, never, AnyType, true>;
|
|
1127
997
|
/**
|
|
@@ -1134,22 +1004,22 @@ export declare const EvoluType: Type<"EvoluType", AnyType, AnyType, EvoluTypeErr
|
|
|
1134
1004
|
* the recursive `TypeNode` shape so composing Types does not repeatedly add its
|
|
1135
1005
|
* compiler cost; {@link EvoluType} bridges that runtime evidence to this type.
|
|
1136
1006
|
*
|
|
1137
|
-
* @group Core
|
|
1007
|
+
* @group Core
|
|
1138
1008
|
*/
|
|
1139
1009
|
export interface AnyType extends TypeNode {
|
|
1140
1010
|
readonly [concreteTypeSymbol]: true;
|
|
1141
1011
|
}
|
|
1142
1012
|
/**
|
|
1143
|
-
* Error returned when
|
|
1013
|
+
* Error returned when {@link EvoluType} rejects a value.
|
|
1144
1014
|
*
|
|
1145
|
-
* @group Core
|
|
1015
|
+
* @group Core
|
|
1146
1016
|
*/
|
|
1147
1017
|
export interface EvoluTypeError extends TypeValueError<"EvoluType"> {
|
|
1148
1018
|
}
|
|
1149
1019
|
/**
|
|
1150
1020
|
* Nominal evidence that a value has one object tag.
|
|
1151
1021
|
*
|
|
1152
|
-
* @group Base
|
|
1022
|
+
* @group Base
|
|
1153
1023
|
*/
|
|
1154
1024
|
export interface ObjectTag<Name extends TypeName> {
|
|
1155
1025
|
readonly [objectTagSymbol]: Name;
|
|
@@ -1157,7 +1027,7 @@ export interface ObjectTag<Name extends TypeName> {
|
|
|
1157
1027
|
/**
|
|
1158
1028
|
* The {@link Type} returned by {@link objectTag}.
|
|
1159
1029
|
*
|
|
1160
|
-
* @group Base
|
|
1030
|
+
* @group Base
|
|
1161
1031
|
*/
|
|
1162
1032
|
export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNode & {
|
|
1163
1033
|
readonly Output: object;
|
|
@@ -1168,7 +1038,7 @@ export interface ObjectTagType<Name extends TypeName, OutputType extends TypeNod
|
|
|
1168
1038
|
/**
|
|
1169
1039
|
* An error returned when an object does not report the expected tag.
|
|
1170
1040
|
*
|
|
1171
|
-
* @group Base
|
|
1041
|
+
* @group Base
|
|
1172
1042
|
*/
|
|
1173
1043
|
export interface ObjectTagError<Expected extends TypeName = TypeName> extends TypeError<"ObjectTag"> {
|
|
1174
1044
|
readonly expected: Expected;
|
|
@@ -1195,9 +1065,21 @@ interface ObjectTagOutputByName {
|
|
|
1195
1065
|
* assumption of the predefined Type. Primitive Outputs are rejected at compile
|
|
1196
1066
|
* time.
|
|
1197
1067
|
*
|
|
1198
|
-
*
|
|
1068
|
+
* ### Example
|
|
1069
|
+
*
|
|
1070
|
+
* ```ts
|
|
1071
|
+
* import { objectTag } from "@evolu/common";
|
|
1072
|
+
*
|
|
1073
|
+
* const DateType = objectTag("Date");
|
|
1074
|
+
* const date = new globalThis.Date("2025-01-01T00:00:00.000Z");
|
|
1075
|
+
*
|
|
1076
|
+
* expectOk(DateType.fromUnknown(date), date);
|
|
1077
|
+
* ```
|
|
1078
|
+
*
|
|
1079
|
+
* @group Base
|
|
1199
1080
|
*/
|
|
1200
1081
|
export declare function objectTag<Name extends keyof ObjectTagOutputByName>(name: ValidateConcreteTypeName<Name>): Type<Name, ObjectTagOutputByName[Name], ObjectTagOutputByName[Name], ObjectTagError<Name>, null, ObjectTagError<Name>, never, ObjectTagOutputByName[Name]>;
|
|
1082
|
+
/** Creates an object-tag Type by refining an existing object Type. */
|
|
1201
1083
|
export declare function objectTag<Name extends TypeName, OutputType extends ConcreteTypeNode & {
|
|
1202
1084
|
readonly Output: object;
|
|
1203
1085
|
}>(name: ValidateConcreteTypeName<Name>, outputType: ValidateOutput<OutputType> & ([ChildTypeNameValidationError<"ObjectTag", OutputType>] extends [never] ? unknown : ChildTypeNameValidationError<"ObjectTag", OutputType>)): ObjectTagType<Name, OutputType>;
|
|
@@ -1207,7 +1089,7 @@ declare const objectTagSymbol: unique symbol;
|
|
|
1207
1089
|
*
|
|
1208
1090
|
* It trusts the reported object tag and does not verify Date internal slots.
|
|
1209
1091
|
*
|
|
1210
|
-
* @group Base
|
|
1092
|
+
* @group Base
|
|
1211
1093
|
*/
|
|
1212
1094
|
export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>;
|
|
1213
1095
|
/**
|
|
@@ -1216,7 +1098,7 @@ export declare const Date: Type<"Date", Date, Date, ObjectTagError<"Date">, null
|
|
|
1216
1098
|
* It trusts the reported object tag and does not verify Uint8Array internal
|
|
1217
1099
|
* slots.
|
|
1218
1100
|
*
|
|
1219
|
-
* @group Base
|
|
1101
|
+
* @group Base
|
|
1220
1102
|
*/
|
|
1221
1103
|
export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, ObjectTagError<"Uint8Array">, null, ObjectTagError<"Uint8Array">, never, Uint8Array<ArrayBufferLike>, true>;
|
|
1222
1104
|
/**
|
|
@@ -1225,7 +1107,7 @@ export declare const Uint8Array: Type<"Uint8Array", Uint8Array<ArrayBufferLike>,
|
|
|
1225
1107
|
* It trusts the reported object tag and does not verify ArrayBuffer internal
|
|
1226
1108
|
* slots.
|
|
1227
1109
|
*
|
|
1228
|
-
* @group Base
|
|
1110
|
+
* @group Base
|
|
1229
1111
|
*/
|
|
1230
1112
|
export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer, ObjectTagError<"ArrayBuffer">, null, ObjectTagError<"ArrayBuffer">, never, ArrayBuffer, true>;
|
|
1231
1113
|
/**
|
|
@@ -1256,25 +1138,33 @@ export declare const ArrayBuffer: Type<"ArrayBuffer", ArrayBuffer, ArrayBuffer,
|
|
|
1256
1138
|
* assert(!UserInstance.is({ name: "Ada" }));
|
|
1257
1139
|
* ```
|
|
1258
1140
|
*
|
|
1259
|
-
* @group Base
|
|
1141
|
+
* @group Base
|
|
1260
1142
|
*/
|
|
1261
1143
|
export declare const instanceOf: <Constructor extends InstanceConstructor>(constructor: ValidateInstanceConstructor<Constructor>) => InstanceOfType<Constructor>;
|
|
1262
1144
|
/**
|
|
1263
1145
|
* A JavaScript class constructor accepted by {@link instanceOf}.
|
|
1264
1146
|
*
|
|
1265
|
-
* @group Base
|
|
1147
|
+
* @group Base
|
|
1266
1148
|
*/
|
|
1267
1149
|
export type InstanceConstructor<Instance extends object = object> = (abstract new (...args: ReadonlyArray<never>) => Instance) & {
|
|
1268
1150
|
readonly name: string;
|
|
1269
1151
|
};
|
|
1270
|
-
/**
|
|
1152
|
+
/**
|
|
1153
|
+
* The {@link Type} returned by {@link instanceOf}.
|
|
1154
|
+
*
|
|
1155
|
+
* @group Base
|
|
1156
|
+
*/
|
|
1271
1157
|
export interface InstanceOfType<Constructor extends InstanceConstructor> extends Type<"InstanceOf", InstanceOfOutput<Constructor>, InstanceOfOutput<Constructor>, InstanceOfError, null, InstanceOfError, never, InstanceOfOutput<Constructor>> {
|
|
1272
1158
|
readonly constructor: Constructor;
|
|
1273
1159
|
}
|
|
1274
1160
|
type InstanceOfOutput<Constructor extends InstanceConstructor> = Constructor extends {
|
|
1275
1161
|
readonly prototype: infer Output extends object;
|
|
1276
1162
|
} ? Output : InstanceType<Constructor>;
|
|
1277
|
-
/**
|
|
1163
|
+
/**
|
|
1164
|
+
* Error returned when a value is not an instance of the expected constructor.
|
|
1165
|
+
*
|
|
1166
|
+
* @group Base
|
|
1167
|
+
*/
|
|
1278
1168
|
export interface InstanceOfError extends TypeValueError<"InstanceOf"> {
|
|
1279
1169
|
readonly constructorName: string;
|
|
1280
1170
|
}
|
|
@@ -1311,7 +1201,11 @@ type InstanceConstructorCompileTimeError = CompileTimeError<"Type", "Constructor
|
|
|
1311
1201
|
* @group Unions
|
|
1312
1202
|
*/
|
|
1313
1203
|
export declare const literal: <const Expected extends Literal>(expected: ValidateLiteral<Expected>) => LiteralType<Expected>;
|
|
1314
|
-
/**
|
|
1204
|
+
/**
|
|
1205
|
+
* The {@link Type} returned by {@link literal}.
|
|
1206
|
+
*
|
|
1207
|
+
* @group Unions
|
|
1208
|
+
*/
|
|
1315
1209
|
export interface LiteralType<Expected extends Literal> extends Type<"Literal", WidenLiteral<Expected>, Expected, LiteralError<Expected>, LiteralParent<Expected>, LiteralError<Expected> | LiteralParentErrors<Expected>, never, CanonicalInputSubset<WidenLiteral<Expected>, CanonicalInputForParent<LiteralParent<Expected>, Expected>>, IdentityEncodingForParent<LiteralParent<Expected>>> {
|
|
1316
1210
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1317
1211
|
readonly expected: Expected;
|
|
@@ -1320,14 +1214,26 @@ type LiteralParent<Expected extends Literal> = Expected extends string ? typeof
|
|
|
1320
1214
|
type LiteralParentErrors<Expected extends Literal> = LiteralParent<Expected> extends infer Parent extends TypeNode ? InferErrors<Parent> : never;
|
|
1321
1215
|
type ValidateLiteral<Expected extends Literal> = IsUnion<Expected> extends false ? {} extends Readonly<Record<`${Expected}`, never>> ? LiteralCompileTimeError : Expected : LiteralCompileTimeError;
|
|
1322
1216
|
type LiteralCompileTimeError = CompileTimeError<"Type", "Expected must be one concrete literal value.">;
|
|
1323
|
-
/**
|
|
1217
|
+
/**
|
|
1218
|
+
* Error returned when a value does not equal the expected literal.
|
|
1219
|
+
*
|
|
1220
|
+
* @group Unions
|
|
1221
|
+
*/
|
|
1324
1222
|
export interface LiteralError<Expected extends Literal = Literal> extends TypeError<"Literal"> {
|
|
1325
1223
|
readonly expected: Expected;
|
|
1326
1224
|
readonly value: unknown;
|
|
1327
1225
|
}
|
|
1328
|
-
/**
|
|
1226
|
+
/**
|
|
1227
|
+
* Literal {@link Type} accepting only `undefined`.
|
|
1228
|
+
*
|
|
1229
|
+
* @group Unions
|
|
1230
|
+
*/
|
|
1329
1231
|
export declare const Undefined: LiteralType<undefined>;
|
|
1330
|
-
/**
|
|
1232
|
+
/**
|
|
1233
|
+
* Literal {@link Type} accepting only `null`.
|
|
1234
|
+
*
|
|
1235
|
+
* @group Unions
|
|
1236
|
+
*/
|
|
1331
1237
|
export declare const Null: LiteralType<null>;
|
|
1332
1238
|
/**
|
|
1333
1239
|
* Union {@link Type}.
|
|
@@ -1352,7 +1258,10 @@ export declare const Null: LiteralType<null>;
|
|
|
1352
1258
|
* within each member.
|
|
1353
1259
|
*
|
|
1354
1260
|
* Member order matters when multiple members accept the same value: validation
|
|
1355
|
-
* and encoding use the first matching member.
|
|
1261
|
+
* and encoding use the first matching member. When member Inputs overlap,
|
|
1262
|
+
* decoding the value emitted by the first member selected for an Output must
|
|
1263
|
+
* reproduce that semantic Output; otherwise the Union violates the round-trip
|
|
1264
|
+
* law.
|
|
1356
1265
|
*
|
|
1357
1266
|
* ### Example
|
|
1358
1267
|
*
|
|
@@ -1389,9 +1298,11 @@ export declare function union<const Expected extends AtLeastTwoReadonlyArray<Lit
|
|
|
1389
1298
|
}): UnionType<{
|
|
1390
1299
|
readonly [Index in keyof Expected]: LiteralType<Expected[Index]>;
|
|
1391
1300
|
}>;
|
|
1301
|
+
/** Creates a Union Type from Type members. */
|
|
1392
1302
|
export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode>>(...members: {
|
|
1393
1303
|
readonly [Index in keyof Members]: ValidateUnionTypeMember<Members[Index]>;
|
|
1394
1304
|
}): UnionType<Members>;
|
|
1305
|
+
/** Creates a Union Type from Type and literal members. */
|
|
1395
1306
|
export declare function union<const Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>>(...members: {
|
|
1396
1307
|
readonly [Index in keyof Members]: ValidateUnionMember<Members[Index]>;
|
|
1397
1308
|
}): UnionType<NormalizeUnionMembers<Members>>;
|
|
@@ -1401,18 +1312,49 @@ export declare function union<const Members extends AtLeastTwoReadonlyArray<Type
|
|
|
1401
1312
|
* This does not make an object property optional. It changes only the values
|
|
1402
1313
|
* accepted when the property is present.
|
|
1403
1314
|
*
|
|
1315
|
+
* ### Example
|
|
1316
|
+
*
|
|
1317
|
+
* ```ts
|
|
1318
|
+
* import { String, undefinedOr } from "@evolu/common";
|
|
1319
|
+
*
|
|
1320
|
+
* const StringOrUndefined = undefinedOr(String);
|
|
1321
|
+
*
|
|
1322
|
+
* expectOk(StringOrUndefined.fromUnknown(undefined), undefined);
|
|
1323
|
+
* ```
|
|
1324
|
+
*
|
|
1404
1325
|
* @group Unions
|
|
1405
1326
|
*/
|
|
1406
1327
|
export declare const undefinedOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Undefined]>;
|
|
1407
1328
|
/**
|
|
1408
1329
|
* Union {@link Type} containing the supplied Type and `null`.
|
|
1409
1330
|
*
|
|
1331
|
+
* ### Example
|
|
1332
|
+
*
|
|
1333
|
+
* ```ts
|
|
1334
|
+
* import { String, nullOr } from "@evolu/common";
|
|
1335
|
+
*
|
|
1336
|
+
* const NullableString = nullOr(String);
|
|
1337
|
+
*
|
|
1338
|
+
* expectOk(NullableString.fromUnknown(null), null);
|
|
1339
|
+
* ```
|
|
1340
|
+
*
|
|
1410
1341
|
* @group Unions
|
|
1411
1342
|
*/
|
|
1412
1343
|
export declare const nullOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null]>;
|
|
1413
1344
|
/**
|
|
1414
1345
|
* Union {@link Type} containing the supplied Type, `null`, and `undefined`.
|
|
1415
1346
|
*
|
|
1347
|
+
* ### Example
|
|
1348
|
+
*
|
|
1349
|
+
* ```ts
|
|
1350
|
+
* import { String, nullishOr } from "@evolu/common";
|
|
1351
|
+
*
|
|
1352
|
+
* const NullishString = nullishOr(String);
|
|
1353
|
+
*
|
|
1354
|
+
* expectOk(NullishString.fromUnknown(undefined), undefined);
|
|
1355
|
+
* expectOk(NullishString.fromUnknown(null), null);
|
|
1356
|
+
* ```
|
|
1357
|
+
*
|
|
1416
1358
|
* @group Unions
|
|
1417
1359
|
*/
|
|
1418
1360
|
export declare const nullishOr: <ValueType extends TypeNode>(type: ValidateUnionTypeMember<ValueType>) => UnionType<readonly [ValueType, typeof Null, typeof Undefined]>;
|
|
@@ -1424,7 +1366,11 @@ type UnionMemberConcreteTypeError = CompileTimeError<"Type", "Union member must
|
|
|
1424
1366
|
type NormalizeUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode | Literal>> = {
|
|
1425
1367
|
readonly [Index in keyof Members]: Members[Index] extends TypeNode ? Members[Index] : Members[Index] extends Literal ? LiteralType<Members[Index]> : never;
|
|
1426
1368
|
} extends infer Normalized extends AtLeastTwoReadonlyArray<TypeNode> ? Normalized : never;
|
|
1427
|
-
/**
|
|
1369
|
+
/**
|
|
1370
|
+
* The {@link Type} returned by {@link union}.
|
|
1371
|
+
*
|
|
1372
|
+
* @group Unions
|
|
1373
|
+
*/
|
|
1428
1374
|
export interface UnionType<Members extends AtLeastTwoReadonlyArray<TypeNode>> extends Type<"Union", Members[number]["Input"], Members[number]["Output"], UnionTypeError<Members>, UnionInputParent<Members>, UnionTypeError<Members>, never, CanonicalInputOf<Members[number]>, AllTypesUseIdentityEncoding<Members[number]>> {
|
|
1429
1375
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1430
1376
|
readonly [reflectedTypesSymbol]?: Members[number];
|
|
@@ -1442,9 +1388,17 @@ type UnionInputTypeError<Members extends AtLeastTwoReadonlyArray<TypeNode>, Root
|
|
|
1442
1388
|
type RootUnionMembers<Members extends AtLeastTwoReadonlyArray<TypeNode>> = {
|
|
1443
1389
|
readonly [Index in keyof Members]: RootType<Members[Index]>;
|
|
1444
1390
|
} extends infer RootMembers extends AtLeastTwoReadonlyArray<TypeNode> ? RootMembers : never;
|
|
1445
|
-
/**
|
|
1391
|
+
/**
|
|
1392
|
+
* Error returned when every member of a {@link union} rejects an input.
|
|
1393
|
+
*
|
|
1394
|
+
* @group Unions
|
|
1395
|
+
*/
|
|
1446
1396
|
export type UnionError<Error extends TypeError = TypeError, MemberError extends UnionMemberError<Error> = UnionMemberError<Error>> = [Error] extends [never] ? never : UnionErrorValue<Error, MemberError>;
|
|
1447
|
-
/**
|
|
1397
|
+
/**
|
|
1398
|
+
* An error returned by one {@link union} member and its index.
|
|
1399
|
+
*
|
|
1400
|
+
* @group Unions
|
|
1401
|
+
*/
|
|
1448
1402
|
export interface UnionMemberError<Error extends TypeError, Index extends number = number> {
|
|
1449
1403
|
readonly index: Index;
|
|
1450
1404
|
readonly error: Error;
|
|
@@ -1472,9 +1426,7 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1472
1426
|
readonly errors: NonEmptyReadonlyArray<MemberError>;
|
|
1473
1427
|
}
|
|
1474
1428
|
/**
|
|
1475
|
-
* Template literal {@link Type}
|
|
1476
|
-
*
|
|
1477
|
-
* Parses and creates structured strings.
|
|
1429
|
+
* Template literal {@link Type} that parses canonical strings into Tuples.
|
|
1478
1430
|
*
|
|
1479
1431
|
* Accepts the same template parts as {@link templateLiteral}: fixed string
|
|
1480
1432
|
* literals and Types canonically encoded as strings. Instead of keeping Output
|
|
@@ -1490,10 +1442,10 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1490
1442
|
* reversibility and keeps capture boundaries unambiguous. Different capture
|
|
1491
1443
|
* Tuples must never encode to the same string. The parser provides predictable
|
|
1492
1444
|
* parsing without pathological backtracking and decodes each capture once, so
|
|
1493
|
-
* adversarial input cannot trigger exponential parser work. Fixed-width
|
|
1494
|
-
* may be adjacent, but only one variable-width capture is allowed.
|
|
1495
|
-
* that could join UTF-16 surrogate halves across parts are
|
|
1496
|
-
* construction.
|
|
1445
|
+
* adversarial input cannot trigger exponential parser work. Fixed-width
|
|
1446
|
+
* captures may be adjacent, but only one variable-width capture is allowed.
|
|
1447
|
+
* Declarations that could join UTF-16 surrogate halves across parts are
|
|
1448
|
+
* rejected during construction.
|
|
1497
1449
|
*
|
|
1498
1450
|
* Keep capture unions reasonably small to avoid excessive compiler work.
|
|
1499
1451
|
*
|
|
@@ -1530,10 +1482,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1530
1482
|
*
|
|
1531
1483
|
* // Parse an unknown string into structured data.
|
|
1532
1484
|
* const result = SupportedLocale.fromUnknown("cs-CZ");
|
|
1533
|
-
*
|
|
1485
|
+
* expectOk(result, ["cs", "CZ"]);
|
|
1534
1486
|
* const locale = result.value;
|
|
1535
1487
|
* expectTypeOf(locale).toEqualTypeOf<SupportedLocale>();
|
|
1536
|
-
* expect(locale).toEqual(["cs", "CZ"]);
|
|
1537
1488
|
* expectErr(SupportedLocale.fromUnknown("cs/CZ"), {
|
|
1538
1489
|
* type: "TemplateLiteral",
|
|
1539
1490
|
* value: "cs/CZ",
|
|
@@ -1592,10 +1543,9 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1592
1543
|
*
|
|
1593
1544
|
* // Decode the string into structured data.
|
|
1594
1545
|
* const result = ItemId.fromUnknown("item-42");
|
|
1595
|
-
*
|
|
1546
|
+
* expectOk(result, [42n]);
|
|
1596
1547
|
* const itemId = result.value;
|
|
1597
1548
|
* expectTypeOf(itemId).toEqualTypeOf<ItemId>();
|
|
1598
|
-
* expect(itemId).toEqual([42n]);
|
|
1599
1549
|
*
|
|
1600
1550
|
* // Encode the structured data into its canonical string.
|
|
1601
1551
|
* const itemIdLiteral = ItemId.to(itemId);
|
|
@@ -1645,14 +1595,22 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1645
1595
|
* @group Template literals
|
|
1646
1596
|
*/
|
|
1647
1597
|
export declare const templateLiteralParser: <const Parts extends TemplateLiteralParts>(...parts: { readonly [Index in keyof Parts]: ValidateTemplateLiteralPart<Parts[Index]>; } & TemplateLiteralValidation<Parts>) => TemplateLiteralParserType<Parts>;
|
|
1648
|
-
/**
|
|
1598
|
+
/**
|
|
1599
|
+
* The parsing {@link Type} returned by {@link templateLiteralParser}.
|
|
1600
|
+
*
|
|
1601
|
+
* @group Template literals
|
|
1602
|
+
*/
|
|
1649
1603
|
export interface TemplateLiteralParserType<Parts extends TemplateLiteralParts> extends Type<"TemplateLiteral", string, TemplateLiteralCaptureTuple<Parts>["Output"], never, TemplateLiteralType<Parts>, InferErrors<TemplateLiteralType<Parts>>, never, TemplateLiteralStringOutput<Parts>, false> {
|
|
1650
1604
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1651
1605
|
readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
|
|
1652
1606
|
readonly output: TemplateLiteralCaptureTuple<Parts>;
|
|
1653
1607
|
readonly parts: Parts;
|
|
1654
1608
|
}
|
|
1655
|
-
/**
|
|
1609
|
+
/**
|
|
1610
|
+
* The validating string {@link Type} returned by {@link templateLiteral}.
|
|
1611
|
+
*
|
|
1612
|
+
* @group Template literals
|
|
1613
|
+
*/
|
|
1656
1614
|
export interface TemplateLiteralType<Parts extends TemplateLiteralParts> extends Type<"TemplateLiteral", string, TemplateLiteralStringOutput<Parts>, TemplateLiteralParseError<Parts>, typeof String, TypeOfError<"String"> | TemplateLiteralParseError<Parts>, never, TemplateLiteralStringOutput<Parts>, true> {
|
|
1657
1615
|
readonly [templateLiteralSyntaxSymbol]: true;
|
|
1658
1616
|
readonly [reflectedTypesSymbol]?: TemplateLiteralCaptureTuple<Parts>;
|
|
@@ -1665,8 +1623,8 @@ export interface TemplateLiteralType<Parts extends TemplateLiteralParts> extends
|
|
|
1665
1623
|
* Creates a canonical string Type from fixed strings and string-encoded Types.
|
|
1666
1624
|
*
|
|
1667
1625
|
* Use this factory when Output should remain a string. Switch to
|
|
1668
|
-
* {@link templateLiteralParser} when the individual Type parts should be
|
|
1669
|
-
*
|
|
1626
|
+
* {@link templateLiteralParser} when the individual Type parts should be decoded
|
|
1627
|
+
* into a Tuple.
|
|
1670
1628
|
*
|
|
1671
1629
|
* ### Example
|
|
1672
1630
|
*
|
|
@@ -1690,7 +1648,11 @@ export declare const templateLiteral: <const Parts extends TemplateLiteralParts>
|
|
|
1690
1648
|
type TemplateLiteralParseError<Parts extends TemplateLiteralParts> = TransformError<"TemplateLiteral", TemplateLiteralIsFrameless<Parts> extends true ? never : TemplateLiteralError, TemplateLiteralCaptureTupleError<Parts>>;
|
|
1691
1649
|
type TemplateLiteralCaptureTupleError<Parts extends TemplateLiteralParts> = TupleElementsError<TemplateLiteralCaptureFromStringError<TemplateLiteralCaptureTypes<Parts>[number]>>;
|
|
1692
1650
|
type TemplateLiteralCaptureFromStringError<T extends TypeNode> = T extends TypeNode ? string extends RootType<T>["Output"] ? TypeFromError<T> : InferErrors<T> : never;
|
|
1693
|
-
/**
|
|
1651
|
+
/**
|
|
1652
|
+
* Error returned when a string does not match a template literal declaration.
|
|
1653
|
+
*
|
|
1654
|
+
* @group Template literals
|
|
1655
|
+
*/
|
|
1694
1656
|
export interface TemplateLiteralError extends TypeError<"TemplateLiteral"> {
|
|
1695
1657
|
readonly value: string;
|
|
1696
1658
|
}
|
|
@@ -1780,72 +1742,19 @@ type TemplateLiteralStringWidth<Value extends string, Width extends ReadonlyArra
|
|
|
1780
1742
|
* });
|
|
1781
1743
|
* ```
|
|
1782
1744
|
*
|
|
1783
|
-
* To reuse a Brand constraint with different parent Types, define a
|
|
1784
|
-
* {@link BrandFactory}.
|
|
1785
|
-
*
|
|
1786
|
-
* ```ts
|
|
1787
|
-
* import {
|
|
1788
|
-
* String,
|
|
1789
|
-
* brand,
|
|
1790
|
-
* err,
|
|
1791
|
-
* minLength,
|
|
1792
|
-
* ok,
|
|
1793
|
-
* type Brand,
|
|
1794
|
-
* type BrandFactory,
|
|
1795
|
-
* type TypeError,
|
|
1796
|
-
* } from "@evolu/common";
|
|
1797
|
-
*
|
|
1798
|
-
* const trimmed: BrandFactory<"Trimmed", string, TrimmedError> = (
|
|
1799
|
-
* parent,
|
|
1800
|
-
* ) =>
|
|
1801
|
-
* brand(
|
|
1802
|
-
* "Trimmed",
|
|
1803
|
-
* parent,
|
|
1804
|
-
* (value) =>
|
|
1805
|
-
* value === value.trim()
|
|
1806
|
-
* ? ok()
|
|
1807
|
-
* : err<TrimmedError>({ type: "Trimmed", value }),
|
|
1808
|
-
* () => "Expected a string without surrounding whitespace.",
|
|
1809
|
-
* );
|
|
1810
|
-
*
|
|
1811
|
-
* const TrimmedString = trimmed(String);
|
|
1812
|
-
* type TrimmedString = typeof TrimmedString.Output;
|
|
1813
|
-
*
|
|
1814
|
-
* expectTypeOf<TrimmedString>().toEqualTypeOf<string & Brand<"Trimmed">>();
|
|
1815
|
-
*
|
|
1816
|
-
* const NonEmptyString = minLength(1)(String);
|
|
1817
|
-
* type NonEmptyString = typeof NonEmptyString.Output;
|
|
1818
|
-
*
|
|
1819
|
-
* expectTypeOf<NonEmptyString>().toEqualTypeOf<
|
|
1820
|
-
* string & Brand<"MinLength1">
|
|
1821
|
-
* >();
|
|
1822
|
-
*
|
|
1823
|
-
* const NonEmptyTrimmedString = minLength(1)(TrimmedString);
|
|
1824
|
-
* type NonEmptyTrimmedString = typeof NonEmptyTrimmedString.Output;
|
|
1825
|
-
*
|
|
1826
|
-
* expectTypeOf<NonEmptyTrimmedString>().toEqualTypeOf<
|
|
1827
|
-
* string & Brand<"Trimmed"> & Brand<"MinLength1">
|
|
1828
|
-
* >();
|
|
1829
|
-
*
|
|
1830
|
-
* interface TrimmedError extends TypeError<"Trimmed"> {
|
|
1831
|
-
* readonly value: string;
|
|
1832
|
-
* }
|
|
1833
|
-
*
|
|
1834
|
-
* // Validation from unknown.
|
|
1835
|
-
* expectOk(NonEmptyTrimmedString.fromUnknown("Evolu"), "Evolu");
|
|
1836
|
-
*
|
|
1837
|
-
* // The typed input selects TrimmedString as the validated boundary.
|
|
1838
|
-
* expectOk(
|
|
1839
|
-
* NonEmptyTrimmedString.from.parent(TrimmedString.orThrow("Evolu")),
|
|
1840
|
-
* "Evolu",
|
|
1841
|
-
* );
|
|
1842
|
-
* ```
|
|
1745
|
+
* To reuse and compose a Brand constraint with different parent Types, define a
|
|
1746
|
+
* {@link BrandFactory}.
|
|
1843
1747
|
*
|
|
1844
|
-
* @group
|
|
1748
|
+
* @group Construction
|
|
1845
1749
|
*/
|
|
1846
1750
|
export declare function brand<Name extends TypeName, ParentType extends ConcreteTypeNode>(name: ValidateConcreteTypeName<Name>, parent: ValidateParent<ParentType>, validate?: (value: ParentType["Output"]) => Result<void, never>): BrandType<ParentType, Name, never>;
|
|
1751
|
+
/** Creates a validated Brand Type with its own error formatter. */
|
|
1847
1752
|
export declare function brand<Name extends TypeName, ParentType extends ConcreteTypeNode, Error extends TypeError<NoInfer<Name>>>(name: Name, parent: ValidateBrandParent<Name, ParentType>, validate: (value: ParentType["Output"]) => Result<void, Error>, formatError: TypeErrorFormatter<NoInfer<Error>>): BrandType<ParentType, Name, Error>;
|
|
1848
|
-
/**
|
|
1753
|
+
/**
|
|
1754
|
+
* The {@link Type} returned by {@link brand}.
|
|
1755
|
+
*
|
|
1756
|
+
* @group Construction
|
|
1757
|
+
*/
|
|
1849
1758
|
export interface BrandType<ParentType extends TypeNode, Name extends TypeName, Error extends TypeError> extends Type<Name, ParentType["Input"], ParentType["Output"] & Brand<Name>, Error, ParentType, Error | InferErrors<ParentType>, ChildCustomFrom<ParentType, ParentType["Output"] & Brand<Name>, Error>, CanonicalInputForChild<ParentType, ParentType["Output"] & Brand<Name>>, IdentityEncodingOf<ParentType>> {
|
|
1850
1759
|
}
|
|
1851
1760
|
/**
|
|
@@ -1878,17 +1787,37 @@ export interface BrandType<ParentType extends TypeNode, Name extends TypeName, E
|
|
|
1878
1787
|
*/
|
|
1879
1788
|
export declare const DateIso: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>;
|
|
1880
1789
|
export type DateIso = typeof DateIso.Output;
|
|
1881
|
-
/**
|
|
1790
|
+
/**
|
|
1791
|
+
* Error returned when a string is not a canonical {@link DateIso}.
|
|
1792
|
+
*
|
|
1793
|
+
* @group String
|
|
1794
|
+
*/
|
|
1882
1795
|
export interface DateIsoError extends TypeError<"DateIso"> {
|
|
1883
1796
|
readonly value: string;
|
|
1884
1797
|
}
|
|
1885
1798
|
/**
|
|
1886
1799
|
* Safely transforms a {@link Date} into a canonical {@link DateIso}.
|
|
1887
1800
|
*
|
|
1888
|
-
*
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1801
|
+
* ### Example
|
|
1802
|
+
*
|
|
1803
|
+
* ```ts
|
|
1804
|
+
* import { DateIsoFromDate } from "@evolu/common";
|
|
1805
|
+
*
|
|
1806
|
+
* const date = new globalThis.Date("2025-01-01T12:00:00.000Z");
|
|
1807
|
+
* const result = DateIsoFromDate.fromUnknown(date);
|
|
1808
|
+
*
|
|
1809
|
+
* expectOk(result, "2025-01-01T12:00:00.000Z");
|
|
1810
|
+
* expect(DateIsoFromDate.to(result.value)).toEqual(date);
|
|
1811
|
+
* ```
|
|
1812
|
+
*
|
|
1813
|
+
* @group String
|
|
1814
|
+
*/
|
|
1815
|
+
export declare const DateIsoFromDate: TransformType<Type<"Date", Date, Date, ObjectTagError<"Date">, null, ObjectTagError<"Date">, never, Date, true>, BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DateIso", DateIsoError>, "DateIsoFromDate", DateIsoFromDateError, Date>;
|
|
1816
|
+
/**
|
|
1817
|
+
* Error returned when a {@link Date} cannot be represented as {@link DateIso}.
|
|
1818
|
+
*
|
|
1819
|
+
* @group String
|
|
1820
|
+
*/
|
|
1892
1821
|
export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
|
|
1893
1822
|
readonly value: globalThis.Date;
|
|
1894
1823
|
}
|
|
@@ -1899,7 +1828,11 @@ export interface DateIsoFromDateError extends TypeError<"DateIsoFromDate"> {
|
|
|
1899
1828
|
*/
|
|
1900
1829
|
export declare const Int64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "Int64", Int64Error>;
|
|
1901
1830
|
export type Int64 = typeof Int64.Output;
|
|
1902
|
-
/**
|
|
1831
|
+
/**
|
|
1832
|
+
* Error returned when a bigint is outside the signed 64-bit {@link Int64} range.
|
|
1833
|
+
*
|
|
1834
|
+
* @group Number
|
|
1835
|
+
*/
|
|
1903
1836
|
export interface Int64Error extends TypeError<"Int64"> {
|
|
1904
1837
|
readonly value: bigint;
|
|
1905
1838
|
}
|
|
@@ -1910,7 +1843,12 @@ export interface Int64Error extends TypeError<"Int64"> {
|
|
|
1910
1843
|
*/
|
|
1911
1844
|
export declare const UInt64: BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "UInt64", UInt64Error>;
|
|
1912
1845
|
export type UInt64 = typeof UInt64.Output;
|
|
1913
|
-
/**
|
|
1846
|
+
/**
|
|
1847
|
+
* Error returned when a bigint is outside the unsigned 64-bit {@link UInt64}
|
|
1848
|
+
* range.
|
|
1849
|
+
*
|
|
1850
|
+
* @group Number
|
|
1851
|
+
*/
|
|
1914
1852
|
export interface UInt64Error extends TypeError<"UInt64"> {
|
|
1915
1853
|
readonly value: bigint;
|
|
1916
1854
|
}
|
|
@@ -1966,7 +1904,7 @@ export interface UInt64Error extends TypeError<"UInt64"> {
|
|
|
1966
1904
|
* For numeric parameters encoded in a Brand name, use
|
|
1967
1905
|
* {@link ValidateBrandFactoryNumber}.
|
|
1968
1906
|
*
|
|
1969
|
-
* @group
|
|
1907
|
+
* @group Construction
|
|
1970
1908
|
*/
|
|
1971
1909
|
export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<Name>> = <ParentType extends ConcreteTypeNode & {
|
|
1972
1910
|
readonly Output: Value;
|
|
@@ -2031,7 +1969,7 @@ export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<N
|
|
|
2031
1969
|
* lessThan(100 - 1)(Number);
|
|
2032
1970
|
* ```
|
|
2033
1971
|
*
|
|
2034
|
-
* @group
|
|
1972
|
+
* @group Construction
|
|
2035
1973
|
*/
|
|
2036
1974
|
export type ValidateBrandFactoryNumber<Value extends number> = IsUnion<Value> extends false ? {} extends Record<`${Value}`, never> ? Value & Readonly<Record<BrandFactoryNumberError, never>> : Value : Value & Readonly<Record<BrandFactoryNumberError, never>>;
|
|
2037
1975
|
type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must be one concrete numeric literal instead of a widened, union, or branded number.">;
|
|
@@ -2062,7 +2000,11 @@ type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must
|
|
|
2062
2000
|
* @group String
|
|
2063
2001
|
*/
|
|
2064
2002
|
export declare const capitalized: BrandFactory<"Capitalized", string, CapitalizedError>;
|
|
2065
|
-
/**
|
|
2003
|
+
/**
|
|
2004
|
+
* Error returned when {@link capitalized} rejects a string.
|
|
2005
|
+
*
|
|
2006
|
+
* @group String
|
|
2007
|
+
*/
|
|
2066
2008
|
export interface CapitalizedError extends TypeError<"Capitalized"> {
|
|
2067
2009
|
readonly value: string;
|
|
2068
2010
|
}
|
|
@@ -2076,10 +2018,24 @@ export type CapitalizedString = typeof CapitalizedString.Output;
|
|
|
2076
2018
|
/**
|
|
2077
2019
|
* String {@link Brand} without surrounding whitespace.
|
|
2078
2020
|
*
|
|
2021
|
+
* ### Example
|
|
2022
|
+
*
|
|
2023
|
+
* ```ts
|
|
2024
|
+
* import { String, trimmed } from "@evolu/common";
|
|
2025
|
+
*
|
|
2026
|
+
* const Trimmed = trimmed(String);
|
|
2027
|
+
*
|
|
2028
|
+
* expectOk(Trimmed.fromUnknown("Evolu"), "Evolu");
|
|
2029
|
+
* ```
|
|
2030
|
+
*
|
|
2079
2031
|
* @group String
|
|
2080
2032
|
*/
|
|
2081
2033
|
export declare const trimmed: BrandFactory<"Trimmed", string, TrimmedError>;
|
|
2082
|
-
/**
|
|
2034
|
+
/**
|
|
2035
|
+
* Error returned when {@link trimmed} rejects a string.
|
|
2036
|
+
*
|
|
2037
|
+
* @group String
|
|
2038
|
+
*/
|
|
2083
2039
|
export interface TrimmedError extends TypeError<"Trimmed"> {
|
|
2084
2040
|
readonly value: string;
|
|
2085
2041
|
}
|
|
@@ -2099,17 +2055,41 @@ export type TrimmedString = typeof TrimmedString.Output;
|
|
|
2099
2055
|
/**
|
|
2100
2056
|
* Trims a string and returns a {@link TrimmedString}.
|
|
2101
2057
|
*
|
|
2058
|
+
* ### Example
|
|
2059
|
+
*
|
|
2060
|
+
* ```ts
|
|
2061
|
+
* import { trim } from "@evolu/common";
|
|
2062
|
+
*
|
|
2063
|
+
* expect(trim(" Evolu ")).toBe("Evolu");
|
|
2064
|
+
* ```
|
|
2065
|
+
*
|
|
2102
2066
|
* @group String
|
|
2103
2067
|
*/
|
|
2104
2068
|
export declare const trim: (value: string) => TrimmedString;
|
|
2105
2069
|
/**
|
|
2106
|
-
* Minimum-length {@link Brand}
|
|
2070
|
+
* Minimum-length {@link Brand} for values whose `length` is at least `min`.
|
|
2071
|
+
*
|
|
2072
|
+
* ### Example
|
|
2073
|
+
*
|
|
2074
|
+
* ```ts
|
|
2075
|
+
* import { String, array, minLength } from "@evolu/common";
|
|
2076
|
+
*
|
|
2077
|
+
* const AtLeastThreeCharacters = minLength(3)(String);
|
|
2078
|
+
* const AtLeastTwoItems = minLength(2)(array(String));
|
|
2079
|
+
*
|
|
2080
|
+
* expectOk(AtLeastThreeCharacters.fromUnknown("abc"), "abc");
|
|
2081
|
+
* expectOk(AtLeastTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
|
|
2082
|
+
* ```
|
|
2107
2083
|
*
|
|
2108
2084
|
* @group String
|
|
2109
2085
|
* @group Collection
|
|
2110
2086
|
*/
|
|
2111
2087
|
export declare const minLength: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`MinLength${Min}`, ValueWithLength, MinLengthError<Min>>;
|
|
2112
|
-
/**
|
|
2088
|
+
/**
|
|
2089
|
+
* Error returned when {@link minLength} rejects a value.
|
|
2090
|
+
*
|
|
2091
|
+
* @group Collection
|
|
2092
|
+
*/
|
|
2113
2093
|
export interface MinLengthError<Min extends number = number> extends TypeError<`MinLength${Min}`> {
|
|
2114
2094
|
readonly value: ValueWithLength;
|
|
2115
2095
|
readonly min: Min;
|
|
@@ -2131,13 +2111,29 @@ export interface MinLengthError<Min extends number = number> extends TypeError<`
|
|
|
2131
2111
|
export declare const NonEmptyTrimmedString: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>;
|
|
2132
2112
|
export type NonEmptyTrimmedString = typeof NonEmptyTrimmedString.Output;
|
|
2133
2113
|
/**
|
|
2134
|
-
* Maximum-length {@link Brand}
|
|
2114
|
+
* Maximum-length {@link Brand} for values whose `length` is at most `max`.
|
|
2115
|
+
*
|
|
2116
|
+
* ### Example
|
|
2117
|
+
*
|
|
2118
|
+
* ```ts
|
|
2119
|
+
* import { String, array, maxLength } from "@evolu/common";
|
|
2120
|
+
*
|
|
2121
|
+
* const AtMostThreeCharacters = maxLength(3)(String);
|
|
2122
|
+
* const AtMostTwoItems = maxLength(2)(array(String));
|
|
2123
|
+
*
|
|
2124
|
+
* expectOk(AtMostThreeCharacters.fromUnknown("abc"), "abc");
|
|
2125
|
+
* expectOk(AtMostTwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
|
|
2126
|
+
* ```
|
|
2135
2127
|
*
|
|
2136
2128
|
* @group String
|
|
2137
2129
|
* @group Collection
|
|
2138
2130
|
*/
|
|
2139
2131
|
export declare const maxLength: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`MaxLength${Max}`, ValueWithLength, MaxLengthError<Max>>;
|
|
2140
|
-
/**
|
|
2132
|
+
/**
|
|
2133
|
+
* Error returned when {@link maxLength} rejects a value.
|
|
2134
|
+
*
|
|
2135
|
+
* @group Collection
|
|
2136
|
+
*/
|
|
2141
2137
|
export interface MaxLengthError<Max extends number = number> extends TypeError<`MaxLength${Max}`> {
|
|
2142
2138
|
readonly value: ValueWithLength;
|
|
2143
2139
|
readonly max: Max;
|
|
@@ -2157,13 +2153,29 @@ export type NonEmptyTrimmedString100 = typeof NonEmptyTrimmedString100.Output;
|
|
|
2157
2153
|
export declare const NonEmptyTrimmedString1000: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "MaxLength1000", MaxLengthError<1000>>;
|
|
2158
2154
|
export type NonEmptyTrimmedString1000 = typeof NonEmptyTrimmedString1000.Output;
|
|
2159
2155
|
/**
|
|
2160
|
-
* Exact-length {@link Brand}
|
|
2156
|
+
* Exact-length {@link Brand} for values whose `length` equals `exact`.
|
|
2157
|
+
*
|
|
2158
|
+
* ### Example
|
|
2159
|
+
*
|
|
2160
|
+
* ```ts
|
|
2161
|
+
* import { String, array, length } from "@evolu/common";
|
|
2162
|
+
*
|
|
2163
|
+
* const ThreeCharacters = length(3)(String);
|
|
2164
|
+
* const TwoItems = length(2)(array(String));
|
|
2165
|
+
*
|
|
2166
|
+
* expectOk(ThreeCharacters.fromUnknown("abc"), "abc");
|
|
2167
|
+
* expectOk(TwoItems.fromUnknown(["a", "b"]), ["a", "b"]);
|
|
2168
|
+
* ```
|
|
2161
2169
|
*
|
|
2162
2170
|
* @group String
|
|
2163
2171
|
* @group Collection
|
|
2164
2172
|
*/
|
|
2165
2173
|
export declare const length: <Exact extends number>(exact: ValidateBrandFactoryNumber<Exact>) => BrandFactory<`Length${Exact}`, ValueWithLength, LengthError<Exact>>;
|
|
2166
|
-
/**
|
|
2174
|
+
/**
|
|
2175
|
+
* Error returned when {@link length} rejects a value.
|
|
2176
|
+
*
|
|
2177
|
+
* @group Collection
|
|
2178
|
+
*/
|
|
2167
2179
|
export interface LengthError<Exact extends number = number> extends TypeError<`Length${Exact}`> {
|
|
2168
2180
|
readonly value: ValueWithLength;
|
|
2169
2181
|
readonly exact: Exact;
|
|
@@ -2197,7 +2209,12 @@ export interface LengthError<Exact extends number = number> extends TypeError<`L
|
|
|
2197
2209
|
* @group String
|
|
2198
2210
|
*/
|
|
2199
2211
|
export declare const regex: <const Name extends TypeName>(name: ValidateConcreteTypeName<Name>, pattern: RegExp) => BrandFactory<Name, string, RegexError<Name>>;
|
|
2200
|
-
/**
|
|
2212
|
+
/**
|
|
2213
|
+
* Error returned when a string does not match the regular expression supplied
|
|
2214
|
+
* to {@link regex}.
|
|
2215
|
+
*
|
|
2216
|
+
* @group String
|
|
2217
|
+
*/
|
|
2201
2218
|
export interface RegexError<Name extends TypeName = TypeName> extends TypeError<Name> {
|
|
2202
2219
|
readonly value: string;
|
|
2203
2220
|
readonly source: string;
|
|
@@ -2224,19 +2241,45 @@ export type UrlSafeString = typeof UrlSafeString.Output;
|
|
|
2224
2241
|
*/
|
|
2225
2242
|
export declare const Base64Url: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Base64Url", Base64UrlError>;
|
|
2226
2243
|
export type Base64Url = typeof Base64Url.Output;
|
|
2227
|
-
/**
|
|
2244
|
+
/**
|
|
2245
|
+
* Error returned when a string is not valid {@link Base64Url} text.
|
|
2246
|
+
*
|
|
2247
|
+
* @group String
|
|
2248
|
+
*/
|
|
2228
2249
|
export interface Base64UrlError extends TypeError<"Base64Url"> {
|
|
2229
2250
|
readonly value: string;
|
|
2230
2251
|
}
|
|
2231
2252
|
/**
|
|
2232
2253
|
* Encodes bytes as {@link Base64Url}.
|
|
2233
2254
|
*
|
|
2255
|
+
* ### Example
|
|
2256
|
+
*
|
|
2257
|
+
* ```ts
|
|
2258
|
+
* import { uint8ArrayToBase64Url } from "@evolu/common";
|
|
2259
|
+
*
|
|
2260
|
+
* expect(uint8ArrayToBase64Url(new Uint8Array([0, 1, 2, 255]))).toBe(
|
|
2261
|
+
* "AAEC_w",
|
|
2262
|
+
* );
|
|
2263
|
+
* ```
|
|
2264
|
+
*
|
|
2234
2265
|
* @group String
|
|
2235
2266
|
*/
|
|
2236
2267
|
export declare const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url;
|
|
2237
2268
|
/**
|
|
2238
2269
|
* Decodes {@link Base64Url} as bytes.
|
|
2239
2270
|
*
|
|
2271
|
+
* ### Example
|
|
2272
|
+
*
|
|
2273
|
+
* ```ts
|
|
2274
|
+
* import { Base64Url, base64UrlToUint8Array } from "@evolu/common";
|
|
2275
|
+
*
|
|
2276
|
+
* const value = Base64Url.orThrow("AAEC_w");
|
|
2277
|
+
*
|
|
2278
|
+
* expect(base64UrlToUint8Array(value)).toEqual(
|
|
2279
|
+
* new Uint8Array([0, 1, 2, 255]),
|
|
2280
|
+
* );
|
|
2281
|
+
* ```
|
|
2282
|
+
*
|
|
2240
2283
|
* @group String
|
|
2241
2284
|
*/
|
|
2242
2285
|
export declare const base64UrlToUint8Array: (value: Base64Url) => Uint8Array;
|
|
@@ -2247,7 +2290,11 @@ export declare const base64UrlToUint8Array: (value: Base64Url) => Uint8Array;
|
|
|
2247
2290
|
*/
|
|
2248
2291
|
export declare const Name: BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "UrlSafeString", RegexError<"UrlSafeString">>, "Name", NameError>;
|
|
2249
2292
|
export type Name = typeof Name.Output;
|
|
2250
|
-
/**
|
|
2293
|
+
/**
|
|
2294
|
+
* Error returned when a string is not a valid {@link Name}.
|
|
2295
|
+
*
|
|
2296
|
+
* @group String
|
|
2297
|
+
*/
|
|
2251
2298
|
export interface NameError extends TypeError<"Name"> {
|
|
2252
2299
|
readonly value: string;
|
|
2253
2300
|
}
|
|
@@ -2271,7 +2318,11 @@ export type SimplePassword = typeof SimplePassword.Output;
|
|
|
2271
2318
|
*/
|
|
2272
2319
|
export declare const Mnemonic: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Mnemonic", MnemonicError>;
|
|
2273
2320
|
export type Mnemonic = typeof Mnemonic.Output;
|
|
2274
|
-
/**
|
|
2321
|
+
/**
|
|
2322
|
+
* Error returned when a string is not a valid English BIP39 {@link Mnemonic}.
|
|
2323
|
+
*
|
|
2324
|
+
* @group String
|
|
2325
|
+
*/
|
|
2275
2326
|
export interface MnemonicError extends TypeError<"Mnemonic"> {
|
|
2276
2327
|
readonly value: string;
|
|
2277
2328
|
}
|
|
@@ -2287,7 +2338,11 @@ export interface MnemonicError extends TypeError<"Mnemonic"> {
|
|
|
2287
2338
|
*/
|
|
2288
2339
|
export declare const Id: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Id", IdError>;
|
|
2289
2340
|
export type Id = typeof Id.Output;
|
|
2290
|
-
/**
|
|
2341
|
+
/**
|
|
2342
|
+
* Error returned when a string is not a valid {@link Id}.
|
|
2343
|
+
*
|
|
2344
|
+
* @group String
|
|
2345
|
+
*/
|
|
2291
2346
|
export interface IdError extends TypeError<"Id"> {
|
|
2292
2347
|
readonly value: string;
|
|
2293
2348
|
}
|
|
@@ -2297,6 +2352,22 @@ export interface IdError extends TypeError<"Id"> {
|
|
|
2297
2352
|
* This is the recommended default because it does not encode creation time.
|
|
2298
2353
|
* Pass a Brand name when the returned Id belongs to one domain entity.
|
|
2299
2354
|
*
|
|
2355
|
+
* ### Example
|
|
2356
|
+
*
|
|
2357
|
+
* ```ts
|
|
2358
|
+
* import {
|
|
2359
|
+
* Id,
|
|
2360
|
+
* createId,
|
|
2361
|
+
* createRandomBytes,
|
|
2362
|
+
* type Brand,
|
|
2363
|
+
* } from "@evolu/common";
|
|
2364
|
+
*
|
|
2365
|
+
* const userId = createId<"User">({ randomBytes: createRandomBytes() });
|
|
2366
|
+
*
|
|
2367
|
+
* expect(Id.is(userId)).toBe(true);
|
|
2368
|
+
* expectTypeOf(userId).toEqualTypeOf<Id & Brand<"User">>();
|
|
2369
|
+
* ```
|
|
2370
|
+
*
|
|
2300
2371
|
* @group String
|
|
2301
2372
|
*/
|
|
2302
2373
|
export declare const createId: <B extends string = never>(deps: RandomBytesDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
|
|
@@ -2331,20 +2402,64 @@ export declare const createIdFromString: <B extends string = never>(value: strin
|
|
|
2331
2402
|
* logs, URLs, and exports. Prefer {@link createId} unless that tradeoff is
|
|
2332
2403
|
* deliberate.
|
|
2333
2404
|
*
|
|
2405
|
+
* ### Example
|
|
2406
|
+
*
|
|
2407
|
+
* ```ts
|
|
2408
|
+
* import {
|
|
2409
|
+
* createIdAsUuidv7,
|
|
2410
|
+
* createRandomBytes,
|
|
2411
|
+
* createTime,
|
|
2412
|
+
* idToIdBytes,
|
|
2413
|
+
* } from "@evolu/common";
|
|
2414
|
+
*
|
|
2415
|
+
* const value = createIdAsUuidv7({
|
|
2416
|
+
* randomBytes: createRandomBytes(),
|
|
2417
|
+
* time: createTime(),
|
|
2418
|
+
* });
|
|
2419
|
+
* const bytes = idToIdBytes(value);
|
|
2420
|
+
*
|
|
2421
|
+
* expect(bytes[6] >> 4).toBe(0x7);
|
|
2422
|
+
* expect(bytes[8] & 0xc0).toBe(0x80);
|
|
2423
|
+
* ```
|
|
2424
|
+
*
|
|
2334
2425
|
* @group String
|
|
2335
2426
|
*/
|
|
2336
2427
|
export declare const createIdAsUuidv7: <B extends string = never>(deps: RandomBytesDep & TimeDep, ..._validation: IdBrandValidation<B>) => CreatedId<B>;
|
|
2337
2428
|
/**
|
|
2338
2429
|
* Table-specific {@link Id} Type.
|
|
2339
2430
|
*
|
|
2431
|
+
* ### Example
|
|
2432
|
+
*
|
|
2433
|
+
* ```ts
|
|
2434
|
+
* import {
|
|
2435
|
+
* createIdFromString,
|
|
2436
|
+
* id,
|
|
2437
|
+
* type Brand,
|
|
2438
|
+
* type Id,
|
|
2439
|
+
* } from "@evolu/common";
|
|
2440
|
+
*
|
|
2441
|
+
* const TodoId = id("Todo");
|
|
2442
|
+
* const todoId = TodoId.orThrow(createIdFromString("todo"));
|
|
2443
|
+
*
|
|
2444
|
+
* expectTypeOf(todoId).toEqualTypeOf<Id & Brand<"Todo">>();
|
|
2445
|
+
* ```
|
|
2446
|
+
*
|
|
2340
2447
|
* @group String
|
|
2341
2448
|
*/
|
|
2342
2449
|
export declare const id: <Table extends TypeName>(table: ValidateTableName<Table>) => TableId<Table>;
|
|
2343
|
-
/**
|
|
2450
|
+
/**
|
|
2451
|
+
* The {@link Type} returned by {@link id} for one table.
|
|
2452
|
+
*
|
|
2453
|
+
* @group String
|
|
2454
|
+
*/
|
|
2344
2455
|
export interface TableId<Table extends TypeName> extends Type<"TableId", string, Id & Brand<Table>, TableIdError<Table>, typeof String, TableIdError<Table> | InferErrors<typeof String>, ChildCustomFrom<typeof String, Id & Brand<Table>, TableIdError<Table>>, CanonicalInputForChild<typeof String, Id & Brand<Table>>, IdentityEncodingOf<typeof String>> {
|
|
2345
2456
|
readonly table: Table;
|
|
2346
2457
|
}
|
|
2347
|
-
/**
|
|
2458
|
+
/**
|
|
2459
|
+
* Error returned when a string is not a valid {@link Id} for the expected table.
|
|
2460
|
+
*
|
|
2461
|
+
* @group String
|
|
2462
|
+
*/
|
|
2348
2463
|
export interface TableIdError<Table extends TypeName = TypeName> extends TypeError<"TableId"> {
|
|
2349
2464
|
readonly table: Table;
|
|
2350
2465
|
readonly value: string;
|
|
@@ -2364,11 +2479,47 @@ type ConcreteIdBrandError = CompileTimeError<"Id", "Brand must be one concrete s
|
|
|
2364
2479
|
*/
|
|
2365
2480
|
export declare const IdBytes: BrandType<BrandType<Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, ObjectTagError<"Uint8Array">, null, ObjectTagError<"Uint8Array">, never, Uint8Array<ArrayBufferLike>, true>, "Length16", LengthError<16>>, "IdBytes", never>;
|
|
2366
2481
|
export type IdBytes = typeof IdBytes.Output;
|
|
2367
|
-
/**
|
|
2482
|
+
/**
|
|
2483
|
+
* Byte length of an {@link IdBytes} value.
|
|
2484
|
+
*
|
|
2485
|
+
* @group String
|
|
2486
|
+
*/
|
|
2368
2487
|
export declare const idBytesTypeValueLength: NonNegativeInt;
|
|
2369
|
-
/**
|
|
2488
|
+
/**
|
|
2489
|
+
* Converts an {@link Id} to {@link IdBytes}.
|
|
2490
|
+
*
|
|
2491
|
+
* ### Example
|
|
2492
|
+
*
|
|
2493
|
+
* ```ts
|
|
2494
|
+
* import { createIdFromString, idToIdBytes } from "@evolu/common";
|
|
2495
|
+
*
|
|
2496
|
+
* const bytes = idToIdBytes(createIdFromString("todo"));
|
|
2497
|
+
*
|
|
2498
|
+
* expect(bytes).toHaveLength(16);
|
|
2499
|
+
* ```
|
|
2500
|
+
*
|
|
2501
|
+
* @group String
|
|
2502
|
+
*/
|
|
2370
2503
|
export declare const idToIdBytes: (value: Id) => IdBytes;
|
|
2371
|
-
/**
|
|
2504
|
+
/**
|
|
2505
|
+
* Converts {@link IdBytes} to an {@link Id}.
|
|
2506
|
+
*
|
|
2507
|
+
* ### Example
|
|
2508
|
+
*
|
|
2509
|
+
* ```ts
|
|
2510
|
+
* import {
|
|
2511
|
+
* createIdFromString,
|
|
2512
|
+
* idBytesToId,
|
|
2513
|
+
* idToIdBytes,
|
|
2514
|
+
* } from "@evolu/common";
|
|
2515
|
+
*
|
|
2516
|
+
* const value = createIdFromString("todo");
|
|
2517
|
+
*
|
|
2518
|
+
* expect(idBytesToId(idToIdBytes(value))).toBe(value);
|
|
2519
|
+
* ```
|
|
2520
|
+
*
|
|
2521
|
+
* @group String
|
|
2522
|
+
*/
|
|
2372
2523
|
export declare const idBytesToId: (value: IdBytes) => Id;
|
|
2373
2524
|
/**
|
|
2374
2525
|
* Decimal string representation of a signed {@link Int64}.
|
|
@@ -2377,7 +2528,11 @@ export declare const idBytesToId: (value: IdBytes) => Id;
|
|
|
2377
2528
|
*/
|
|
2378
2529
|
export declare const Int64String: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Int64String", Int64StringError>;
|
|
2379
2530
|
export type Int64String = typeof Int64String.Output;
|
|
2380
|
-
/**
|
|
2531
|
+
/**
|
|
2532
|
+
* Error returned when a string is not a canonical {@link Int64String}.
|
|
2533
|
+
*
|
|
2534
|
+
* @group Number
|
|
2535
|
+
*/
|
|
2381
2536
|
export interface Int64StringError extends TypeError<"Int64String"> {
|
|
2382
2537
|
readonly value: string;
|
|
2383
2538
|
}
|
|
@@ -2388,16 +2543,41 @@ export interface Int64StringError extends TypeError<"Int64String"> {
|
|
|
2388
2543
|
* text, including SQLite queries that cast INTEGER values to TEXT to avoid a
|
|
2389
2544
|
* lossy JavaScript number conversion.
|
|
2390
2545
|
*
|
|
2546
|
+
* ### Example
|
|
2547
|
+
*
|
|
2548
|
+
* ```ts
|
|
2549
|
+
* import { Int64FromInt64String } from "@evolu/common";
|
|
2550
|
+
*
|
|
2551
|
+
* const result = Int64FromInt64String.fromUnknown("9223372036854775807");
|
|
2552
|
+
*
|
|
2553
|
+
* expectOk(result, 9223372036854775807n);
|
|
2554
|
+
* expect(Int64FromInt64String.to(result.value)).toBe("9223372036854775807");
|
|
2555
|
+
* ```
|
|
2556
|
+
*
|
|
2391
2557
|
* @group Number
|
|
2392
2558
|
*/
|
|
2393
2559
|
export declare const Int64FromInt64String: TransformType<BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Trimmed", TrimmedError>, "MinLength1", MinLengthError<1>>, "Int64String", Int64StringError>, BrandType<Type<"BigInt", bigint, bigint, TypeOfError<"BigInt">, null, TypeOfError<"BigInt">, never, bigint, true>, "Int64", Int64Error>, "Int64FromInt64String", never, string & Brand<"Trimmed"> & Brand<"MinLength1"> & Brand<"Int64String">>;
|
|
2394
2560
|
/**
|
|
2395
2561
|
* Number {@link Brand} requiring a value greater than or equal to zero.
|
|
2396
2562
|
*
|
|
2563
|
+
* ### Example
|
|
2564
|
+
*
|
|
2565
|
+
* ```ts
|
|
2566
|
+
* import { Number, nonNegative } from "@evolu/common";
|
|
2567
|
+
*
|
|
2568
|
+
* const NonNegative = nonNegative(Number);
|
|
2569
|
+
*
|
|
2570
|
+
* expectOk(NonNegative.fromUnknown(0), 0);
|
|
2571
|
+
* ```
|
|
2572
|
+
*
|
|
2397
2573
|
* @group Number
|
|
2398
2574
|
*/
|
|
2399
2575
|
export declare const nonNegative: BrandFactory<"NonNegative", number, NonNegativeError>;
|
|
2400
|
-
/**
|
|
2576
|
+
/**
|
|
2577
|
+
* Error returned when {@link nonNegative} rejects a number.
|
|
2578
|
+
*
|
|
2579
|
+
* @group Number
|
|
2580
|
+
*/
|
|
2401
2581
|
export interface NonNegativeError extends TypeError<"NonNegative"> {
|
|
2402
2582
|
readonly value: number;
|
|
2403
2583
|
}
|
|
@@ -2411,10 +2591,24 @@ export type NonNegativeNumber = typeof NonNegativeNumber.Output;
|
|
|
2411
2591
|
/**
|
|
2412
2592
|
* Number {@link Brand} requiring a value greater than zero.
|
|
2413
2593
|
*
|
|
2594
|
+
* ### Example
|
|
2595
|
+
*
|
|
2596
|
+
* ```ts
|
|
2597
|
+
* import { Number, positive } from "@evolu/common";
|
|
2598
|
+
*
|
|
2599
|
+
* const Positive = positive(Number);
|
|
2600
|
+
*
|
|
2601
|
+
* expectOk(Positive.fromUnknown(1), 1);
|
|
2602
|
+
* ```
|
|
2603
|
+
*
|
|
2414
2604
|
* @group Number
|
|
2415
2605
|
*/
|
|
2416
2606
|
export declare const positive: BrandFactory<"Positive", number, PositiveError>;
|
|
2417
|
-
/**
|
|
2607
|
+
/**
|
|
2608
|
+
* Error returned when {@link positive} rejects a number.
|
|
2609
|
+
*
|
|
2610
|
+
* @group Number
|
|
2611
|
+
*/
|
|
2418
2612
|
export interface PositiveError extends TypeError<"Positive"> {
|
|
2419
2613
|
readonly value: number;
|
|
2420
2614
|
}
|
|
@@ -2431,10 +2625,24 @@ export type PositiveNumber = typeof PositiveNumber.Output;
|
|
|
2431
2625
|
/**
|
|
2432
2626
|
* Number {@link Brand} requiring a value less than or equal to zero.
|
|
2433
2627
|
*
|
|
2628
|
+
* ### Example
|
|
2629
|
+
*
|
|
2630
|
+
* ```ts
|
|
2631
|
+
* import { Number, nonPositive } from "@evolu/common";
|
|
2632
|
+
*
|
|
2633
|
+
* const NonPositive = nonPositive(Number);
|
|
2634
|
+
*
|
|
2635
|
+
* expectOk(NonPositive.fromUnknown(0), 0);
|
|
2636
|
+
* ```
|
|
2637
|
+
*
|
|
2434
2638
|
* @group Number
|
|
2435
2639
|
*/
|
|
2436
2640
|
export declare const nonPositive: BrandFactory<"NonPositive", number, NonPositiveError>;
|
|
2437
|
-
/**
|
|
2641
|
+
/**
|
|
2642
|
+
* Error returned when {@link nonPositive} rejects a number.
|
|
2643
|
+
*
|
|
2644
|
+
* @group Number
|
|
2645
|
+
*/
|
|
2438
2646
|
export interface NonPositiveError extends TypeError<"NonPositive"> {
|
|
2439
2647
|
readonly value: number;
|
|
2440
2648
|
}
|
|
@@ -2448,10 +2656,24 @@ export type NonPositiveNumber = typeof NonPositiveNumber.Output;
|
|
|
2448
2656
|
/**
|
|
2449
2657
|
* Number {@link Brand} requiring a value less than zero.
|
|
2450
2658
|
*
|
|
2659
|
+
* ### Example
|
|
2660
|
+
*
|
|
2661
|
+
* ```ts
|
|
2662
|
+
* import { Number, negative } from "@evolu/common";
|
|
2663
|
+
*
|
|
2664
|
+
* const Negative = negative(Number);
|
|
2665
|
+
*
|
|
2666
|
+
* expectOk(Negative.fromUnknown(-1), -1);
|
|
2667
|
+
* ```
|
|
2668
|
+
*
|
|
2451
2669
|
* @group Number
|
|
2452
2670
|
*/
|
|
2453
2671
|
export declare const negative: BrandFactory<"Negative", number, NegativeError>;
|
|
2454
|
-
/**
|
|
2672
|
+
/**
|
|
2673
|
+
* Error returned when {@link negative} rejects a number.
|
|
2674
|
+
*
|
|
2675
|
+
* @group Number
|
|
2676
|
+
*/
|
|
2455
2677
|
export interface NegativeError extends TypeError<"Negative"> {
|
|
2456
2678
|
readonly value: number;
|
|
2457
2679
|
}
|
|
@@ -2468,10 +2690,24 @@ export type NegativeNumber = typeof NegativeNumber.Output;
|
|
|
2468
2690
|
/**
|
|
2469
2691
|
* Number {@link Brand} requiring a value other than `NaN`.
|
|
2470
2692
|
*
|
|
2693
|
+
* ### Example
|
|
2694
|
+
*
|
|
2695
|
+
* ```ts
|
|
2696
|
+
* import { Number, nonNaN } from "@evolu/common";
|
|
2697
|
+
*
|
|
2698
|
+
* const NonNaN = nonNaN(Number);
|
|
2699
|
+
*
|
|
2700
|
+
* expectOk(NonNaN.fromUnknown(Infinity), Infinity);
|
|
2701
|
+
* ```
|
|
2702
|
+
*
|
|
2471
2703
|
* @group Number
|
|
2472
2704
|
*/
|
|
2473
2705
|
export declare const nonNaN: BrandFactory<"NonNaN", number, NonNaNError>;
|
|
2474
|
-
/**
|
|
2706
|
+
/**
|
|
2707
|
+
* Error returned when {@link nonNaN} rejects `NaN`.
|
|
2708
|
+
*
|
|
2709
|
+
* @group Number
|
|
2710
|
+
*/
|
|
2475
2711
|
export interface NonNaNError extends TypeError<"NonNaN"> {
|
|
2476
2712
|
readonly value: number;
|
|
2477
2713
|
}
|
|
@@ -2490,10 +2726,24 @@ export type NonNaNNumber = typeof NonNaNNumber.Output;
|
|
|
2490
2726
|
/**
|
|
2491
2727
|
* Number {@link Brand} requiring a finite value.
|
|
2492
2728
|
*
|
|
2729
|
+
* ### Example
|
|
2730
|
+
*
|
|
2731
|
+
* ```ts
|
|
2732
|
+
* import { Number, finite } from "@evolu/common";
|
|
2733
|
+
*
|
|
2734
|
+
* const Finite = finite(Number);
|
|
2735
|
+
*
|
|
2736
|
+
* expectOk(Finite.fromUnknown(42), 42);
|
|
2737
|
+
* ```
|
|
2738
|
+
*
|
|
2493
2739
|
* @group Number
|
|
2494
2740
|
*/
|
|
2495
2741
|
export declare const finite: BrandFactory<"Finite", number, FiniteError>;
|
|
2496
|
-
/**
|
|
2742
|
+
/**
|
|
2743
|
+
* Error returned when {@link finite} rejects a non-finite number.
|
|
2744
|
+
*
|
|
2745
|
+
* @group Number
|
|
2746
|
+
*/
|
|
2497
2747
|
export interface FiniteError extends TypeError<"Finite"> {
|
|
2498
2748
|
readonly value: number;
|
|
2499
2749
|
}
|
|
@@ -2541,7 +2791,11 @@ export type PositiveFiniteNumber = typeof PositiveFiniteNumber.Output;
|
|
|
2541
2791
|
* @group Number
|
|
2542
2792
|
*/
|
|
2543
2793
|
export declare const int: BrandFactory<"Int", number, IntError>;
|
|
2544
|
-
/**
|
|
2794
|
+
/**
|
|
2795
|
+
* Error returned when {@link int} rejects a number that is not a safe integer.
|
|
2796
|
+
*
|
|
2797
|
+
* @group Number
|
|
2798
|
+
*/
|
|
2545
2799
|
export interface IntError extends TypeError<"Int"> {
|
|
2546
2800
|
readonly value: number;
|
|
2547
2801
|
}
|
|
@@ -2607,10 +2861,24 @@ export type NegativeInt = typeof NegativeInt.Output;
|
|
|
2607
2861
|
/**
|
|
2608
2862
|
* Number {@link Brand} requiring a value greater than `min`.
|
|
2609
2863
|
*
|
|
2864
|
+
* ### Example
|
|
2865
|
+
*
|
|
2866
|
+
* ```ts
|
|
2867
|
+
* import { Number, greaterThan } from "@evolu/common";
|
|
2868
|
+
*
|
|
2869
|
+
* const GreaterThanTen = greaterThan(10)(Number);
|
|
2870
|
+
*
|
|
2871
|
+
* expectOk(GreaterThanTen.fromUnknown(11), 11);
|
|
2872
|
+
* ```
|
|
2873
|
+
*
|
|
2610
2874
|
* @group Number
|
|
2611
2875
|
*/
|
|
2612
2876
|
export declare const greaterThan: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThan${Min}`, number, GreaterThanError<Min>>;
|
|
2613
|
-
/**
|
|
2877
|
+
/**
|
|
2878
|
+
* Error returned when {@link greaterThan} rejects a number.
|
|
2879
|
+
*
|
|
2880
|
+
* @group Number
|
|
2881
|
+
*/
|
|
2614
2882
|
export interface GreaterThanError<Min extends number = number> extends TypeError<`GreaterThan${Min}`> {
|
|
2615
2883
|
readonly value: number;
|
|
2616
2884
|
readonly min: Min;
|
|
@@ -2618,10 +2886,24 @@ export interface GreaterThanError<Min extends number = number> extends TypeError
|
|
|
2618
2886
|
/**
|
|
2619
2887
|
* Number {@link Brand} requiring a value greater than or equal to `min`.
|
|
2620
2888
|
*
|
|
2889
|
+
* ### Example
|
|
2890
|
+
*
|
|
2891
|
+
* ```ts
|
|
2892
|
+
* import { Number, greaterThanOrEqualTo } from "@evolu/common";
|
|
2893
|
+
*
|
|
2894
|
+
* const AtLeastTen = greaterThanOrEqualTo(10)(Number);
|
|
2895
|
+
*
|
|
2896
|
+
* expectOk(AtLeastTen.fromUnknown(10), 10);
|
|
2897
|
+
* ```
|
|
2898
|
+
*
|
|
2621
2899
|
* @group Number
|
|
2622
2900
|
*/
|
|
2623
2901
|
export declare const greaterThanOrEqualTo: <Min extends number>(min: ValidateBrandFactoryNumber<Min>) => BrandFactory<`GreaterThanOrEqualTo${Min}`, number, GreaterThanOrEqualToError<Min>>;
|
|
2624
|
-
/**
|
|
2902
|
+
/**
|
|
2903
|
+
* Error returned when {@link greaterThanOrEqualTo} rejects a number.
|
|
2904
|
+
*
|
|
2905
|
+
* @group Number
|
|
2906
|
+
*/
|
|
2625
2907
|
export interface GreaterThanOrEqualToError<Min extends number = number> extends TypeError<`GreaterThanOrEqualTo${Min}`> {
|
|
2626
2908
|
readonly value: number;
|
|
2627
2909
|
readonly min: Min;
|
|
@@ -2629,10 +2911,24 @@ export interface GreaterThanOrEqualToError<Min extends number = number> extends
|
|
|
2629
2911
|
/**
|
|
2630
2912
|
* Number {@link Brand} requiring a value less than `max`.
|
|
2631
2913
|
*
|
|
2914
|
+
* ### Example
|
|
2915
|
+
*
|
|
2916
|
+
* ```ts
|
|
2917
|
+
* import { Number, lessThan } from "@evolu/common";
|
|
2918
|
+
*
|
|
2919
|
+
* const LessThanTen = lessThan(10)(Number);
|
|
2920
|
+
*
|
|
2921
|
+
* expectOk(LessThanTen.fromUnknown(9), 9);
|
|
2922
|
+
* ```
|
|
2923
|
+
*
|
|
2632
2924
|
* @group Number
|
|
2633
2925
|
*/
|
|
2634
2926
|
export declare const lessThan: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThan${Max}`, number, LessThanError<Max>>;
|
|
2635
|
-
/**
|
|
2927
|
+
/**
|
|
2928
|
+
* Error returned when {@link lessThan} rejects a number.
|
|
2929
|
+
*
|
|
2930
|
+
* @group Number
|
|
2931
|
+
*/
|
|
2636
2932
|
export interface LessThanError<Max extends number = number> extends TypeError<`LessThan${Max}`> {
|
|
2637
2933
|
readonly value: number;
|
|
2638
2934
|
readonly max: Max;
|
|
@@ -2647,10 +2943,24 @@ export type Age = typeof Age.Output;
|
|
|
2647
2943
|
/**
|
|
2648
2944
|
* Number {@link Brand} requiring a value less than or equal to `max`.
|
|
2649
2945
|
*
|
|
2946
|
+
* ### Example
|
|
2947
|
+
*
|
|
2948
|
+
* ```ts
|
|
2949
|
+
* import { Number, lessThanOrEqualTo } from "@evolu/common";
|
|
2950
|
+
*
|
|
2951
|
+
* const AtMostTen = lessThanOrEqualTo(10)(Number);
|
|
2952
|
+
*
|
|
2953
|
+
* expectOk(AtMostTen.fromUnknown(10), 10);
|
|
2954
|
+
* ```
|
|
2955
|
+
*
|
|
2650
2956
|
* @group Number
|
|
2651
2957
|
*/
|
|
2652
2958
|
export declare const lessThanOrEqualTo: <Max extends number>(max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`LessThanOrEqualTo${Max}`, number, LessThanOrEqualToError<Max>>;
|
|
2653
|
-
/**
|
|
2959
|
+
/**
|
|
2960
|
+
* Error returned when {@link lessThanOrEqualTo} rejects a number.
|
|
2961
|
+
*
|
|
2962
|
+
* @group Number
|
|
2963
|
+
*/
|
|
2654
2964
|
export interface LessThanOrEqualToError<Max extends number = number> extends TypeError<`LessThanOrEqualTo${Max}`> {
|
|
2655
2965
|
readonly value: number;
|
|
2656
2966
|
readonly max: Max;
|
|
@@ -2707,17 +3017,35 @@ export type Ratio = typeof Ratio.Output;
|
|
|
2707
3017
|
*/
|
|
2708
3018
|
export declare const DecimalString: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DecimalString", DecimalStringError>;
|
|
2709
3019
|
export type DecimalString = typeof DecimalString.Output;
|
|
2710
|
-
/**
|
|
3020
|
+
/**
|
|
3021
|
+
* Error returned when a string is not a canonical {@link DecimalString}.
|
|
3022
|
+
*
|
|
3023
|
+
* @group Number
|
|
3024
|
+
*/
|
|
2711
3025
|
export interface DecimalStringError extends TypeError<"DecimalString"> {
|
|
2712
3026
|
readonly value: string;
|
|
2713
3027
|
}
|
|
2714
3028
|
/**
|
|
2715
3029
|
* {@link DecimalString} Brand requiring a value greater than or equal to zero.
|
|
2716
3030
|
*
|
|
3031
|
+
* ### Example
|
|
3032
|
+
*
|
|
3033
|
+
* ```ts
|
|
3034
|
+
* import { DecimalString, nonNegativeDecimalString } from "@evolu/common";
|
|
3035
|
+
*
|
|
3036
|
+
* const NonNegative = nonNegativeDecimalString(DecimalString);
|
|
3037
|
+
*
|
|
3038
|
+
* expectOk(NonNegative.fromUnknown("0.5"), "0.5");
|
|
3039
|
+
* ```
|
|
3040
|
+
*
|
|
2717
3041
|
* @group Number
|
|
2718
3042
|
*/
|
|
2719
3043
|
export declare const nonNegativeDecimalString: BrandFactory<"NonNegativeDecimalString", DecimalString, NonNegativeDecimalStringError>;
|
|
2720
|
-
/**
|
|
3044
|
+
/**
|
|
3045
|
+
* Error returned when {@link nonNegativeDecimalString} rejects a decimal string.
|
|
3046
|
+
*
|
|
3047
|
+
* @group Number
|
|
3048
|
+
*/
|
|
2721
3049
|
export interface NonNegativeDecimalStringError extends TypeError<"NonNegativeDecimalString"> {
|
|
2722
3050
|
readonly value: string;
|
|
2723
3051
|
}
|
|
@@ -2731,10 +3059,24 @@ export type NonNegativeDecimalString = typeof NonNegativeDecimalString.Output;
|
|
|
2731
3059
|
/**
|
|
2732
3060
|
* {@link DecimalString} Brand requiring a value greater than zero.
|
|
2733
3061
|
*
|
|
3062
|
+
* ### Example
|
|
3063
|
+
*
|
|
3064
|
+
* ```ts
|
|
3065
|
+
* import { DecimalString, positiveDecimalString } from "@evolu/common";
|
|
3066
|
+
*
|
|
3067
|
+
* const Positive = positiveDecimalString(DecimalString);
|
|
3068
|
+
*
|
|
3069
|
+
* expectOk(Positive.fromUnknown("0.5"), "0.5");
|
|
3070
|
+
* ```
|
|
3071
|
+
*
|
|
2734
3072
|
* @group Number
|
|
2735
3073
|
*/
|
|
2736
3074
|
export declare const positiveDecimalString: BrandFactory<"PositiveDecimalString", DecimalString, PositiveDecimalStringError>;
|
|
2737
|
-
/**
|
|
3075
|
+
/**
|
|
3076
|
+
* Error returned when {@link positiveDecimalString} rejects a decimal string.
|
|
3077
|
+
*
|
|
3078
|
+
* @group Number
|
|
3079
|
+
*/
|
|
2738
3080
|
export interface PositiveDecimalStringError extends TypeError<"PositiveDecimalString"> {
|
|
2739
3081
|
readonly value: string;
|
|
2740
3082
|
}
|
|
@@ -2749,12 +3091,26 @@ export interface PositiveDecimalStringError extends TypeError<"PositiveDecimalSt
|
|
|
2749
3091
|
export declare const PositiveDecimalString: BrandType<BrandType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "DecimalString", DecimalStringError>, "NonNegativeDecimalString", NonNegativeDecimalStringError>, "PositiveDecimalString", PositiveDecimalStringError>;
|
|
2750
3092
|
export type PositiveDecimalString = typeof PositiveDecimalString.Output;
|
|
2751
3093
|
/**
|
|
2752
|
-
* {@link DecimalString} Brand requiring a value less than or equal to zero.
|
|
3094
|
+
* {@link DecimalString} Brand requiring a value less than or equal to zero.
|
|
3095
|
+
*
|
|
3096
|
+
* ### Example
|
|
3097
|
+
*
|
|
3098
|
+
* ```ts
|
|
3099
|
+
* import { DecimalString, nonPositiveDecimalString } from "@evolu/common";
|
|
3100
|
+
*
|
|
3101
|
+
* const NonPositive = nonPositiveDecimalString(DecimalString);
|
|
3102
|
+
*
|
|
3103
|
+
* expectOk(NonPositive.fromUnknown("-0.5"), "-0.5");
|
|
3104
|
+
* ```
|
|
3105
|
+
*
|
|
3106
|
+
* @group Number
|
|
3107
|
+
*/
|
|
3108
|
+
export declare const nonPositiveDecimalString: BrandFactory<"NonPositiveDecimalString", DecimalString, NonPositiveDecimalStringError>;
|
|
3109
|
+
/**
|
|
3110
|
+
* Error returned when {@link nonPositiveDecimalString} rejects a decimal string.
|
|
2753
3111
|
*
|
|
2754
3112
|
* @group Number
|
|
2755
3113
|
*/
|
|
2756
|
-
export declare const nonPositiveDecimalString: BrandFactory<"NonPositiveDecimalString", DecimalString, NonPositiveDecimalStringError>;
|
|
2757
|
-
/** @group Number */
|
|
2758
3114
|
export interface NonPositiveDecimalStringError extends TypeError<"NonPositiveDecimalString"> {
|
|
2759
3115
|
readonly value: string;
|
|
2760
3116
|
}
|
|
@@ -2768,10 +3124,24 @@ export type NonPositiveDecimalString = typeof NonPositiveDecimalString.Output;
|
|
|
2768
3124
|
/**
|
|
2769
3125
|
* {@link DecimalString} Brand requiring a value less than zero.
|
|
2770
3126
|
*
|
|
3127
|
+
* ### Example
|
|
3128
|
+
*
|
|
3129
|
+
* ```ts
|
|
3130
|
+
* import { DecimalString, negativeDecimalString } from "@evolu/common";
|
|
3131
|
+
*
|
|
3132
|
+
* const Negative = negativeDecimalString(DecimalString);
|
|
3133
|
+
*
|
|
3134
|
+
* expectOk(Negative.fromUnknown("-0.5"), "-0.5");
|
|
3135
|
+
* ```
|
|
3136
|
+
*
|
|
2771
3137
|
* @group Number
|
|
2772
3138
|
*/
|
|
2773
3139
|
export declare const negativeDecimalString: BrandFactory<"NegativeDecimalString", DecimalString, NegativeDecimalStringError>;
|
|
2774
|
-
/**
|
|
3140
|
+
/**
|
|
3141
|
+
* Error returned when {@link negativeDecimalString} rejects a decimal string.
|
|
3142
|
+
*
|
|
3143
|
+
* @group Number
|
|
3144
|
+
*/
|
|
2775
3145
|
export interface NegativeDecimalStringError extends TypeError<"NegativeDecimalString"> {
|
|
2776
3146
|
readonly value: string;
|
|
2777
3147
|
}
|
|
@@ -2818,7 +3188,11 @@ export type NegativeDecimalString = typeof NegativeDecimalString.Output;
|
|
|
2818
3188
|
* @group Number
|
|
2819
3189
|
*/
|
|
2820
3190
|
export declare const multipleOf: <const Divisor extends string>(divisor: ValidateMultipleOfDivisor<Divisor>) => BrandFactory<`MultipleOf${Divisor}`, number, MultipleOfError<Divisor>>;
|
|
2821
|
-
/**
|
|
3191
|
+
/**
|
|
3192
|
+
* Error returned when {@link multipleOf} rejects a number.
|
|
3193
|
+
*
|
|
3194
|
+
* @group Number
|
|
3195
|
+
*/
|
|
2822
3196
|
export interface MultipleOfError<Divisor extends string = string> extends TypeError<`MultipleOf${Divisor}`> {
|
|
2823
3197
|
readonly value: number;
|
|
2824
3198
|
readonly divisor: Divisor;
|
|
@@ -2834,10 +3208,24 @@ type MultipleOfDivisorError = CompileTimeError<"MultipleOf", 'Divisor must be on
|
|
|
2834
3208
|
/**
|
|
2835
3209
|
* Number {@link Brand} requiring a value within an inclusive range.
|
|
2836
3210
|
*
|
|
3211
|
+
* ### Example
|
|
3212
|
+
*
|
|
3213
|
+
* ```ts
|
|
3214
|
+
* import { Number, between } from "@evolu/common";
|
|
3215
|
+
*
|
|
3216
|
+
* const Percentage = between(0, 100)(Number);
|
|
3217
|
+
*
|
|
3218
|
+
* expectOk(Percentage.fromUnknown(75), 75);
|
|
3219
|
+
* ```
|
|
3220
|
+
*
|
|
2837
3221
|
* @group Number
|
|
2838
3222
|
*/
|
|
2839
3223
|
export declare const between: <Min extends number, Max extends number>(min: ValidateBrandFactoryNumber<Min>, max: ValidateBrandFactoryNumber<Max>) => BrandFactory<`Between${Min}-${Max}`, number, BetweenError<Min, Max>>;
|
|
2840
|
-
/**
|
|
3224
|
+
/**
|
|
3225
|
+
* Error returned when {@link between} rejects a number.
|
|
3226
|
+
*
|
|
3227
|
+
* @group Number
|
|
3228
|
+
*/
|
|
2841
3229
|
export interface BetweenError<Min extends number = number, Max extends number = number> extends TypeError<`Between${Min}-${Max}`> {
|
|
2842
3230
|
readonly value: number;
|
|
2843
3231
|
readonly min: Min;
|
|
@@ -2894,7 +3282,11 @@ export interface BetweenError<Min extends number = number, Max extends number =
|
|
|
2894
3282
|
* @group Collection
|
|
2895
3283
|
*/
|
|
2896
3284
|
export declare const array: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => ArrayType<ElementType>;
|
|
2897
|
-
/**
|
|
3285
|
+
/**
|
|
3286
|
+
* The homogeneous readonly-array {@link Type} returned by {@link array}.
|
|
3287
|
+
*
|
|
3288
|
+
* @group Collection
|
|
3289
|
+
*/
|
|
2898
3290
|
export interface ArrayType<ElementType extends TypeNode> extends Type<"Array", ReadonlyArray<ElementType["Input"]>, ReadonlyArray<ElementType["Output"]>, ArrayNodeError<ElementType>, ArrayParent<ElementType>, ArrayError<InferErrors<ElementType>>, ArrayCustomFrom<ElementType>, ReadonlyArray<CanonicalInputOf<ElementType>>, AllTypesUseIdentityEncoding<ElementType>> {
|
|
2899
3291
|
readonly [reflectedTypesSymbol]?: ElementType;
|
|
2900
3292
|
readonly element: ElementType;
|
|
@@ -2915,42 +3307,78 @@ type ArrayParent<ElementType extends TypeNode> = [
|
|
|
2915
3307
|
type ArrayNodeError<ElementType extends TypeNode> = [
|
|
2916
3308
|
ElementType["parent"]
|
|
2917
3309
|
] extends [TypeNode] ? ArrayElementsError<ElementType["Error"]> : ArrayError<ElementType["Error"]>;
|
|
2918
|
-
/**
|
|
3310
|
+
/**
|
|
3311
|
+
* Error returned by {@link array} for a non-array value or invalid array items.
|
|
3312
|
+
*
|
|
3313
|
+
* @group Collection
|
|
3314
|
+
*/
|
|
2919
3315
|
export type ArrayError<Error extends TypeError = TypeError> = ArrayNotArrayError | ArrayItemsErrorValue<Error, true>;
|
|
2920
|
-
/**
|
|
3316
|
+
/**
|
|
3317
|
+
* Error returned when an {@link array} input is not an array.
|
|
3318
|
+
*
|
|
3319
|
+
* @group Collection
|
|
3320
|
+
*/
|
|
2921
3321
|
export interface ArrayNotArrayError extends TypeError<"Array"> {
|
|
2922
3322
|
readonly reason: {
|
|
2923
3323
|
readonly kind: "NotArray";
|
|
2924
3324
|
readonly value: unknown;
|
|
2925
3325
|
};
|
|
2926
3326
|
}
|
|
2927
|
-
/**
|
|
3327
|
+
/**
|
|
3328
|
+
* An {@link array} error containing structural or element issues.
|
|
3329
|
+
*
|
|
3330
|
+
* @group Collection
|
|
3331
|
+
*/
|
|
2928
3332
|
export type ArrayItemsError<Error extends TypeError> = ArrayItemsErrorValue<Error, true>;
|
|
2929
|
-
/**
|
|
3333
|
+
/**
|
|
3334
|
+
* One structural or element issue found by {@link array}.
|
|
3335
|
+
*
|
|
3336
|
+
* @group Collection
|
|
3337
|
+
*/
|
|
2930
3338
|
export type ArrayIssue<Error extends TypeError> = ArrayStructuralIssue | ArrayElementIssue<Error>;
|
|
2931
|
-
/**
|
|
3339
|
+
/**
|
|
3340
|
+
* A missing array element.
|
|
3341
|
+
*
|
|
3342
|
+
* @group Collection
|
|
3343
|
+
*/
|
|
2932
3344
|
export interface ArrayHoleIssue {
|
|
2933
3345
|
readonly kind: "Hole";
|
|
2934
3346
|
readonly index: number;
|
|
2935
3347
|
}
|
|
2936
|
-
/**
|
|
3348
|
+
/**
|
|
3349
|
+
* An array element defined by an accessor instead of a data property.
|
|
3350
|
+
*
|
|
3351
|
+
* @group Collection
|
|
3352
|
+
*/
|
|
2937
3353
|
export interface ArrayAccessorIssue {
|
|
2938
3354
|
readonly kind: "Accessor";
|
|
2939
3355
|
readonly index: number;
|
|
2940
3356
|
}
|
|
2941
|
-
/**
|
|
3357
|
+
/**
|
|
3358
|
+
* An own array property other than `length` or an indexed element.
|
|
3359
|
+
*
|
|
3360
|
+
* @group Collection
|
|
3361
|
+
*/
|
|
2942
3362
|
export interface ArrayExcessPropertyIssue {
|
|
2943
3363
|
readonly kind: "ExcessProperty";
|
|
2944
3364
|
readonly key: string | symbol;
|
|
2945
3365
|
}
|
|
2946
3366
|
type ArrayStructuralIssue = ArrayHoleIssue | ArrayAccessorIssue | ArrayExcessPropertyIssue;
|
|
2947
|
-
/**
|
|
3367
|
+
/**
|
|
3368
|
+
* An invalid array element and its index.
|
|
3369
|
+
*
|
|
3370
|
+
* @group Collection
|
|
3371
|
+
*/
|
|
2948
3372
|
export type ArrayElementIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
2949
3373
|
readonly kind: "Element";
|
|
2950
3374
|
readonly index: number;
|
|
2951
3375
|
readonly error: Error;
|
|
2952
3376
|
} : never;
|
|
2953
|
-
/**
|
|
3377
|
+
/**
|
|
3378
|
+
* An {@link array} error containing element errors from a typed boundary.
|
|
3379
|
+
*
|
|
3380
|
+
* @group Collection
|
|
3381
|
+
*/
|
|
2954
3382
|
export type ArrayElementsError<Error extends TypeError> = [Error] extends [
|
|
2955
3383
|
never
|
|
2956
3384
|
] ? never : ArrayItemsErrorValue<Error, false>;
|
|
@@ -2968,10 +3396,25 @@ interface ArrayItemsErrorValue<Error extends TypeError, IncludeStructuralIssues
|
|
|
2968
3396
|
* iteration order. Classification uses the realm-neutral object tag and
|
|
2969
3397
|
* prototype structure under Evolu Type's trusted JavaScript policy.
|
|
2970
3398
|
*
|
|
3399
|
+
* ### Example
|
|
3400
|
+
*
|
|
3401
|
+
* ```ts
|
|
3402
|
+
* import { String, set } from "@evolu/common";
|
|
3403
|
+
*
|
|
3404
|
+
* const Tags = set(String);
|
|
3405
|
+
* const tags = new Set(["local-first", "offline"]);
|
|
3406
|
+
*
|
|
3407
|
+
* expectOk(Tags.fromUnknown(tags), tags);
|
|
3408
|
+
* ```
|
|
3409
|
+
*
|
|
2971
3410
|
* @group Collection
|
|
2972
3411
|
*/
|
|
2973
3412
|
export declare const set: <ElementType extends ConcreteTypeNode>(element: ValidateElement<ElementType>) => SetType<ElementType>;
|
|
2974
|
-
/**
|
|
3413
|
+
/**
|
|
3414
|
+
* The homogeneous readonly-set {@link Type} returned by {@link set}.
|
|
3415
|
+
*
|
|
3416
|
+
* @group Collection
|
|
3417
|
+
*/
|
|
2975
3418
|
export interface SetType<ElementType extends TypeNode> extends Type<"Set", ReadonlySet<ElementType["Input"]>, ReadonlySet<ElementType["Output"]>, SetNodeError<ElementType>, SetParent<ElementType>, SetError<InferErrors<ElementType>>, SetCustomFrom<ElementType>, ReadonlySet<CanonicalInputOf<ElementType>>, AllTypesUseIdentityEncoding<ElementType>> {
|
|
2976
3419
|
readonly [reflectedTypesSymbol]?: ElementType;
|
|
2977
3420
|
readonly element: ElementType;
|
|
@@ -2991,9 +3434,18 @@ type SetParent<ElementType extends TypeNode> = [ElementType["parent"]] extends [
|
|
|
2991
3434
|
type SetNodeError<ElementType extends TypeNode> = [
|
|
2992
3435
|
ElementType["parent"]
|
|
2993
3436
|
] extends [TypeNode] ? SetElementsError<ElementType["Error"]> : SetError<ElementType["Error"]>;
|
|
2994
|
-
/**
|
|
3437
|
+
/**
|
|
3438
|
+
* Error returned by {@link set} for a non-Set value, an invalid Set prototype,
|
|
3439
|
+
* or invalid Set items.
|
|
3440
|
+
*
|
|
3441
|
+
* @group Collection
|
|
3442
|
+
*/
|
|
2995
3443
|
export type SetError<Error extends TypeError = TypeError> = SetNotSetError | SetUnexpectedPrototypeError | SetItemsErrorValue<Error, true>;
|
|
2996
|
-
/**
|
|
3444
|
+
/**
|
|
3445
|
+
* Error returned when a {@link set} input is not a Set.
|
|
3446
|
+
*
|
|
3447
|
+
* @group Collection
|
|
3448
|
+
*/
|
|
2997
3449
|
export interface SetNotSetError extends TypeError<"Set"> {
|
|
2998
3450
|
readonly reason: {
|
|
2999
3451
|
readonly kind: "NotSet";
|
|
@@ -3011,21 +3463,37 @@ export interface SetUnexpectedPrototypeError extends TypeError<"Set"> {
|
|
|
3011
3463
|
readonly value: ReadonlySet<unknown>;
|
|
3012
3464
|
};
|
|
3013
3465
|
}
|
|
3014
|
-
/**
|
|
3466
|
+
/**
|
|
3467
|
+
* An own property found on a Set value.
|
|
3468
|
+
*
|
|
3469
|
+
* @group Collection
|
|
3470
|
+
*/
|
|
3015
3471
|
export interface SetExcessPropertyIssue {
|
|
3016
3472
|
readonly kind: "ExcessProperty";
|
|
3017
3473
|
readonly key: string | symbol;
|
|
3018
3474
|
}
|
|
3019
3475
|
type SetStructuralIssue = SetExcessPropertyIssue;
|
|
3020
|
-
/**
|
|
3476
|
+
/**
|
|
3477
|
+
* An invalid Set element and its iteration index.
|
|
3478
|
+
*
|
|
3479
|
+
* @group Collection
|
|
3480
|
+
*/
|
|
3021
3481
|
export type SetElementIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
3022
3482
|
readonly kind: "Element";
|
|
3023
3483
|
readonly index: number;
|
|
3024
3484
|
readonly error: Error;
|
|
3025
3485
|
} : never;
|
|
3026
|
-
/**
|
|
3486
|
+
/**
|
|
3487
|
+
* A {@link set} error containing structural or element issues.
|
|
3488
|
+
*
|
|
3489
|
+
* @group Collection
|
|
3490
|
+
*/
|
|
3027
3491
|
export type SetItemsError<Error extends TypeError> = SetItemsErrorValue<Error, true>;
|
|
3028
|
-
/**
|
|
3492
|
+
/**
|
|
3493
|
+
* A {@link set} error containing element errors from a typed boundary.
|
|
3494
|
+
*
|
|
3495
|
+
* @group Collection
|
|
3496
|
+
*/
|
|
3029
3497
|
export type SetElementsError<Error extends TypeError> = [Error] extends [never] ? never : SetItemsErrorValue<Error, false>;
|
|
3030
3498
|
interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues extends boolean> extends TypeError<"Set"> {
|
|
3031
3499
|
readonly reason: {
|
|
@@ -3058,17 +3526,12 @@ interface SetItemsErrorValue<Error extends TypeError, IncludeStructuralIssues ex
|
|
|
3058
3526
|
* ### Example
|
|
3059
3527
|
*
|
|
3060
3528
|
* ```ts
|
|
3061
|
-
* import {
|
|
3062
|
-
*
|
|
3063
|
-
* const NumberFromString = transform("NumberFromString", String, Number, {
|
|
3064
|
-
* from: (value) => ok(globalThis.Number(value)),
|
|
3065
|
-
* to: globalThis.String,
|
|
3066
|
-
* });
|
|
3529
|
+
* import { Int64FromInt64String, String, tuple } from "@evolu/common";
|
|
3067
3530
|
*
|
|
3068
|
-
* const Entry = tuple(String,
|
|
3531
|
+
* const Entry = tuple(String, Int64FromInt64String);
|
|
3069
3532
|
*
|
|
3070
|
-
* expectOk(Entry.fromUnknown(["count", "1"]), ["count",
|
|
3071
|
-
* expectOk(Entry.from.parent(["count", "1"]), ["count",
|
|
3533
|
+
* expectOk(Entry.fromUnknown(["count", "1"]), ["count", 1n]);
|
|
3534
|
+
* expectOk(Entry.from.parent(["count", "1"]), ["count", 1n]);
|
|
3072
3535
|
* ```
|
|
3073
3536
|
*
|
|
3074
3537
|
* @group Collection
|
|
@@ -3267,7 +3730,7 @@ type PlainObjectError = ObjectError<Readonly<Record<never, never>>, ObjectProper
|
|
|
3267
3730
|
* values have their own Types, and {@link instanceOf} when an instance belongs
|
|
3268
3731
|
* to the domain.
|
|
3269
3732
|
*
|
|
3270
|
-
* @group Base
|
|
3733
|
+
* @group Base
|
|
3271
3734
|
*/
|
|
3272
3735
|
export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>, PlainObjectError, null, PlainObjectError, never, Readonly<Record<string, unknown>>>;
|
|
3273
3736
|
/**
|
|
@@ -3300,20 +3763,13 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3300
3763
|
*
|
|
3301
3764
|
* ```ts
|
|
3302
3765
|
* import {
|
|
3303
|
-
*
|
|
3766
|
+
* Int64FromInt64String,
|
|
3304
3767
|
* String,
|
|
3305
|
-
* ok,
|
|
3306
3768
|
* record,
|
|
3307
|
-
*
|
|
3308
|
-
* type Result,
|
|
3769
|
+
* type Int64,
|
|
3309
3770
|
* } from "@evolu/common";
|
|
3310
3771
|
*
|
|
3311
|
-
* const
|
|
3312
|
-
* from: (value) => ok(globalThis.Number(value)),
|
|
3313
|
-
* to: globalThis.String,
|
|
3314
|
-
* });
|
|
3315
|
-
*
|
|
3316
|
-
* const ScoresByUser = record(String, ScoreFromString);
|
|
3772
|
+
* const ScoresByUser = record(String, Int64FromInt64String);
|
|
3317
3773
|
* type ScoresByUser = typeof ScoresByUser.Output;
|
|
3318
3774
|
*
|
|
3319
3775
|
* // Validate an unknown value.
|
|
@@ -3322,7 +3778,7 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3322
3778
|
* grace: "20",
|
|
3323
3779
|
* });
|
|
3324
3780
|
*
|
|
3325
|
-
* expectOk(scoresFromUnknown, { ada:
|
|
3781
|
+
* expectOk(scoresFromUnknown, { ada: 10n, grace: 20n });
|
|
3326
3782
|
*
|
|
3327
3783
|
* // Validate keys and values with their root Types.
|
|
3328
3784
|
* const scoresInput = ScoresByUser.parent.fromUnknown({
|
|
@@ -3334,11 +3790,10 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3334
3790
|
* // Run the remaining key and value stages.
|
|
3335
3791
|
* const scoresFromInput = ScoresByUser.from.parent(scoresInput.value);
|
|
3336
3792
|
*
|
|
3337
|
-
*
|
|
3338
|
-
*
|
|
3793
|
+
* expectOk(scoresFromInput, { ada: 10n, grace: 20n });
|
|
3794
|
+
* expectTypeOf(scoresFromInput.value).toEqualTypeOf<
|
|
3795
|
+
* Readonly<Partial<Record<string, Int64>>>
|
|
3339
3796
|
* >();
|
|
3340
|
-
*
|
|
3341
|
-
* expectOk(scoresFromInput, { ada: 10, grace: 20 });
|
|
3342
3797
|
* ```
|
|
3343
3798
|
*
|
|
3344
3799
|
* Note that TypeScript does not model an object's runtime prototype. This can
|
|
@@ -3382,7 +3837,11 @@ export declare const Object: Type<"Object", Readonly<Record<string, unknown>>, R
|
|
|
3382
3837
|
* @group Objects
|
|
3383
3838
|
*/
|
|
3384
3839
|
export declare const record: <KeyType extends ConcreteTypeNode, ValueType extends ConcreteTypeNode>(key: ValidateRecordKeyType<KeyType>, value: ValidateRecordValueType<ValueType>) => RecordType<KeyType, ValueType>;
|
|
3385
|
-
/**
|
|
3840
|
+
/**
|
|
3841
|
+
* The {@link Type} returned by {@link record}.
|
|
3842
|
+
*
|
|
3843
|
+
* @group Objects
|
|
3844
|
+
*/
|
|
3386
3845
|
export interface RecordType<KeyType extends TypeNode, ValueType extends TypeNode> extends Type<"Record", RecordShape<KeyType, ValueType, "Input">, RecordShape<KeyType, ValueType, "Output">, RecordNodeError<KeyType, ValueType>, RecordParent<KeyType, ValueType>, RecordError<InferErrors<KeyType>, InferErrors<ValueType>, RecordCollisionFor<KeyType>>, never, CanonicalInputSubset<RecordShape<KeyType, ValueType, "Input">, RecordShape<KeyType, ValueType, "CanonicalInput">>, AllTypesUseIdentityEncoding<KeyType | ValueType>> {
|
|
3387
3846
|
readonly [reflectedTypesSymbol]?: KeyType | ValueType;
|
|
3388
3847
|
readonly key: KeyType;
|
|
@@ -3412,16 +3871,28 @@ type ValidateRecordValueType<T extends ConcreteTypeNode> = IsUnion<T> extends fa
|
|
|
3412
3871
|
type RecordKeyConcreteTypeError = CompileTimeError<"Type", "Record key must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
|
|
3413
3872
|
type RecordValueConcreteTypeError = CompileTimeError<"Type", "Record value must use one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
|
|
3414
3873
|
type RecordKeyStringTypeError = CompileTimeError<"Type", "Record key Type Input and Output must extend string.">;
|
|
3415
|
-
/**
|
|
3874
|
+
/**
|
|
3875
|
+
* Error returned while validating a {@link record} and its entries.
|
|
3876
|
+
*
|
|
3877
|
+
* @group Objects
|
|
3878
|
+
*/
|
|
3416
3879
|
export type RecordError<KeyError extends TypeError = TypeError, ValueError extends TypeError = TypeError, Collision extends RecordCollisionIssue = RecordCollisionIssue> = RecordNotRecordError | RecordNotPlainRecordError | RecordEntriesErrorValue<KeyError, ValueError, Collision | RecordAccessorIssue | RecordNonEnumerableIssue>;
|
|
3417
|
-
/**
|
|
3880
|
+
/**
|
|
3881
|
+
* Error returned when a {@link record} input is not an object.
|
|
3882
|
+
*
|
|
3883
|
+
* @group Objects
|
|
3884
|
+
*/
|
|
3418
3885
|
export interface RecordNotRecordError extends TypeError<"Record"> {
|
|
3419
3886
|
readonly reason: {
|
|
3420
3887
|
readonly kind: "NotRecord";
|
|
3421
3888
|
readonly value: unknown;
|
|
3422
3889
|
};
|
|
3423
3890
|
}
|
|
3424
|
-
/**
|
|
3891
|
+
/**
|
|
3892
|
+
* Error returned when a {@link record} input is not a plain object.
|
|
3893
|
+
*
|
|
3894
|
+
* @group Objects
|
|
3895
|
+
*/
|
|
3425
3896
|
export interface RecordNotPlainRecordError extends TypeError<"Record"> {
|
|
3426
3897
|
readonly reason: {
|
|
3427
3898
|
readonly kind: "NotPlainRecord";
|
|
@@ -3438,9 +3909,17 @@ export interface RecordNotPlainRecordError extends TypeError<"Record"> {
|
|
|
3438
3909
|
* @group Objects
|
|
3439
3910
|
*/
|
|
3440
3911
|
export type RecordEntriesError<KeyError extends TypeError, ValueError extends TypeError, StructuralIssue extends RecordStructuralIssue = RecordCollisionIssue> = [KeyError | ValueError | StructuralIssue] extends [never] ? never : RecordEntriesErrorValue<KeyError, ValueError, StructuralIssue>;
|
|
3441
|
-
/**
|
|
3912
|
+
/**
|
|
3913
|
+
* An invalid key, value, or property structure in a {@link record}.
|
|
3914
|
+
*
|
|
3915
|
+
* @group Objects
|
|
3916
|
+
*/
|
|
3442
3917
|
export type RecordIssue<KeyError extends TypeError, ValueError extends TypeError, StructuralIssue extends RecordStructuralIssue = RecordCollisionIssue> = RecordKeyIssue<KeyError> | RecordValueIssue<ValueError> | StructuralIssue;
|
|
3443
|
-
/**
|
|
3918
|
+
/**
|
|
3919
|
+
* A property-structure issue returned by {@link record}.
|
|
3920
|
+
*
|
|
3921
|
+
* @group Objects
|
|
3922
|
+
*/
|
|
3444
3923
|
export type RecordStructuralIssue = RecordAccessorIssue | RecordCollisionIssue | RecordNonEnumerableIssue;
|
|
3445
3924
|
/**
|
|
3446
3925
|
* An accessor property rejected by {@link record}.
|
|
@@ -3460,19 +3939,31 @@ export interface RecordNonEnumerableIssue {
|
|
|
3460
3939
|
readonly kind: "NonEnumerable";
|
|
3461
3940
|
readonly key: string | symbol;
|
|
3462
3941
|
}
|
|
3463
|
-
/**
|
|
3942
|
+
/**
|
|
3943
|
+
* An invalid key and its source property key in a {@link record}.
|
|
3944
|
+
*
|
|
3945
|
+
* @group Objects
|
|
3946
|
+
*/
|
|
3464
3947
|
export type RecordKeyIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
3465
3948
|
readonly kind: "Key";
|
|
3466
3949
|
readonly key: string | symbol;
|
|
3467
3950
|
readonly error: Error;
|
|
3468
3951
|
} : never;
|
|
3469
|
-
/**
|
|
3952
|
+
/**
|
|
3953
|
+
* An invalid value and its property key in a {@link record}.
|
|
3954
|
+
*
|
|
3955
|
+
* @group Objects
|
|
3956
|
+
*/
|
|
3470
3957
|
export type RecordValueIssue<Error extends TypeError> = Error extends TypeError ? {
|
|
3471
3958
|
readonly kind: "Value";
|
|
3472
3959
|
readonly key: string | symbol;
|
|
3473
3960
|
readonly error: Error;
|
|
3474
3961
|
} : never;
|
|
3475
|
-
/**
|
|
3962
|
+
/**
|
|
3963
|
+
* Two {@link record} keys that decode to the same output key.
|
|
3964
|
+
*
|
|
3965
|
+
* @group Objects
|
|
3966
|
+
*/
|
|
3476
3967
|
export interface RecordCollisionIssue {
|
|
3477
3968
|
readonly kind: "Collision";
|
|
3478
3969
|
readonly key: string | symbol;
|
|
@@ -3563,48 +4054,38 @@ type ObjectProperty = ObjectProps[string];
|
|
|
3563
4054
|
*
|
|
3564
4055
|
* ```ts
|
|
3565
4056
|
* import {
|
|
3566
|
-
*
|
|
4057
|
+
* Int64FromInt64String,
|
|
3567
4058
|
* String,
|
|
3568
4059
|
* object,
|
|
3569
|
-
* ok,
|
|
3570
|
-
* transform,
|
|
3571
4060
|
* type InferType,
|
|
3572
|
-
* type Result,
|
|
3573
4061
|
* } from "@evolu/common";
|
|
3574
4062
|
*
|
|
3575
|
-
* const AgeFromString = transform("AgeFromString", String, Number, {
|
|
3576
|
-
* from: (value) => ok(globalThis.Number(value)),
|
|
3577
|
-
* to: globalThis.String,
|
|
3578
|
-
* });
|
|
3579
|
-
*
|
|
3580
4063
|
* const User = object({
|
|
3581
4064
|
* name: String,
|
|
3582
|
-
*
|
|
4065
|
+
* loginCount: Int64FromInt64String,
|
|
3583
4066
|
* });
|
|
3584
4067
|
* interface User extends InferType<typeof User> {}
|
|
3585
4068
|
*
|
|
3586
4069
|
* // Validate an unknown value.
|
|
3587
|
-
* const userFromUnknown = User.fromUnknown({
|
|
4070
|
+
* const userFromUnknown = User.fromUnknown({
|
|
4071
|
+
* name: "Ada",
|
|
4072
|
+
* loginCount: "42",
|
|
4073
|
+
* });
|
|
3588
4074
|
*
|
|
3589
|
-
* expectOk(userFromUnknown, { name: "Ada",
|
|
4075
|
+
* expectOk(userFromUnknown, { name: "Ada", loginCount: 42n });
|
|
3590
4076
|
*
|
|
3591
4077
|
* // Validate the object and root property Types.
|
|
3592
4078
|
* const userInput = User.parent.fromUnknown({
|
|
3593
4079
|
* name: "Ada",
|
|
3594
|
-
*
|
|
4080
|
+
* loginCount: "42",
|
|
3595
4081
|
* });
|
|
3596
|
-
* expectOk(userInput, { name: "Ada",
|
|
4082
|
+
* expectOk(userInput, { name: "Ada", loginCount: "42" });
|
|
3597
4083
|
*
|
|
3598
4084
|
* // Run the remaining property stages.
|
|
3599
|
-
* const userFromInput
|
|
3600
|
-
* { readonly name: string; readonly age: number },
|
|
3601
|
-
* never
|
|
3602
|
-
* > = User.from.parent(userInput.value);
|
|
4085
|
+
* const userFromInput = User.from.parent(userInput.value);
|
|
3603
4086
|
*
|
|
3604
|
-
*
|
|
3605
|
-
*
|
|
3606
|
-
* >();
|
|
3607
|
-
* expectOk(userFromInput, { name: "Ada", age: 42 });
|
|
4087
|
+
* expectOk(userFromInput, { name: "Ada", loginCount: 42n });
|
|
4088
|
+
* expectTypeOf(userFromInput.value).toExtend<User>();
|
|
3608
4089
|
* ```
|
|
3609
4090
|
*
|
|
3610
4091
|
* Note that TypeScript does not model an object's runtime prototype. This can
|
|
@@ -3652,6 +4133,7 @@ type ObjectProperty = ObjectProps[string];
|
|
|
3652
4133
|
* @group Objects
|
|
3653
4134
|
*/
|
|
3654
4135
|
export declare function object<const Props extends ObjectProps>(props: Props, ...validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]): StrictObjectType<Props>;
|
|
4136
|
+
/** Creates an Object Type with additional record properties. */
|
|
3655
4137
|
export declare function object<const Props extends ObjectProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(props: Props, record: Rest, ...validation: [
|
|
3656
4138
|
ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>
|
|
3657
4139
|
] extends [never] ? [] : [
|
|
@@ -3693,7 +4175,11 @@ type ObjectRecordKeyTypeError = CompileTimeError<"Type", "Object Record key must
|
|
|
3693
4175
|
type ObjectRecordInputTypeError = CompileTimeError<"Type", "Every declared property Type Input must extend the Object Record value Type Input.">;
|
|
3694
4176
|
type ObjectRecordOutputTypeError = CompileTimeError<"Type", "Every declared property Type Output must extend the Object Record value Type Output.">;
|
|
3695
4177
|
type ObjectRecordCanonicalInputTypeError = CompileTimeError<"Type", "Every declared property Type CanonicalInput must extend the Object Record value Type CanonicalInput.">;
|
|
3696
|
-
/**
|
|
4178
|
+
/**
|
|
4179
|
+
* The {@link Type} returned by {@link object}.
|
|
4180
|
+
*
|
|
4181
|
+
* @group Objects
|
|
4182
|
+
*/
|
|
3697
4183
|
export type ObjectType<Props extends ObjectProps, Rest extends ObjectRecordTypeNode | undefined = undefined> = Rest extends ObjectRecordTypeNode ? ObjectWithRecordType<Props, Rest> : StrictObjectType<Props>;
|
|
3698
4184
|
type StrictObjectType<Props extends ObjectProps> = Type<"Object", StrictObjectShape<Props, "Input">, StrictObjectShape<Props, "Output">, [
|
|
3699
4185
|
StrictObjectParents<Props>
|
|
@@ -3883,7 +4369,11 @@ type ObjectRestFromParentError<Rest extends ObjectRecordTypeNode | undefined> =
|
|
|
3883
4369
|
* @group Objects
|
|
3884
4370
|
*/
|
|
3885
4371
|
export declare const partial: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<PartialObjectProps<Props>>;
|
|
3886
|
-
/**
|
|
4372
|
+
/**
|
|
4373
|
+
* Maps every required object property Type to an optional property.
|
|
4374
|
+
*
|
|
4375
|
+
* @group Objects
|
|
4376
|
+
*/
|
|
3887
4377
|
export type PartialObjectProps<Props extends ObjectProps> = {
|
|
3888
4378
|
readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends TypeNode ? OptionalProperty<Props[Key]> : never;
|
|
3889
4379
|
};
|
|
@@ -3915,13 +4405,29 @@ export type PartialObjectProps<Props extends ObjectProps> = {
|
|
|
3915
4405
|
* @group Objects
|
|
3916
4406
|
*/
|
|
3917
4407
|
export declare const nullableToOptional: <const Props extends ObjectProps>(props: Props, ..._validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]) => ObjectType<NullableToOptionalProps<Props>>;
|
|
3918
|
-
/**
|
|
4408
|
+
/**
|
|
4409
|
+
* Maps object properties whose Union Type includes {@link Null} to optional
|
|
4410
|
+
* properties.
|
|
4411
|
+
*
|
|
4412
|
+
* @group Objects
|
|
4413
|
+
*/
|
|
3919
4414
|
export type NullableToOptionalProps<Props extends ObjectProps> = {
|
|
3920
4415
|
readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends UnionType<infer Members> ? typeof Null extends Members[number] ? OptionalProperty<Props[Key]> : Props[Key] : Props[Key];
|
|
3921
4416
|
};
|
|
3922
4417
|
/**
|
|
3923
4418
|
* Object {@link Type} without the selected declared properties.
|
|
3924
4419
|
*
|
|
4420
|
+
* ### Example
|
|
4421
|
+
*
|
|
4422
|
+
* ```ts
|
|
4423
|
+
* import { String, object, omit } from "@evolu/common";
|
|
4424
|
+
*
|
|
4425
|
+
* const User = object({ name: String, password: String });
|
|
4426
|
+
* const PublicUser = omit(User, "password");
|
|
4427
|
+
*
|
|
4428
|
+
* expectOk(PublicUser.fromUnknown({ name: "Ada" }), { name: "Ada" });
|
|
4429
|
+
* ```
|
|
4430
|
+
*
|
|
3925
4431
|
* @group Objects
|
|
3926
4432
|
*/
|
|
3927
4433
|
export declare const omit: <const Props extends ObjectProps, const Keys extends ReadonlyArray<keyof Props>, Rest extends ObjectRecordTypeNode | undefined = undefined>(objectType: ObjectType<Props, Rest>, ...keys: Keys & ([ValidateOmitKeys<Keys>] extends [never] ? unknown : readonly [ValidationFailure<ValidateOmitKeys<Keys>>])) => ObjectType<Omit<Props, Keys[number]>, Rest>;
|
|
@@ -3931,11 +4437,11 @@ type ValidateOmitKeys<Keys extends ReadonlyArray<PropertyKey>> = number extends
|
|
|
3931
4437
|
type OmitKeysTupleError = CompileTimeError<"Type", "Omitted keys must use one concrete finite tuple.">;
|
|
3932
4438
|
type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must be one concrete property key.">;
|
|
3933
4439
|
/**
|
|
3934
|
-
*
|
|
4440
|
+
* Creates a {@link Type} for {@link Result} values.
|
|
3935
4441
|
*
|
|
3936
4442
|
* Use this to validate Results crossing a storage, worker, API, or other
|
|
3937
|
-
* serialization boundary.
|
|
3938
|
-
* successful value is the inner domain Result described by `okType` and
|
|
4443
|
+
* serialization boundary. `fromUnknown` returns an outer validation Result.
|
|
4444
|
+
* Its successful value is the inner domain Result described by `okType` and
|
|
3939
4445
|
* `errorType`.
|
|
3940
4446
|
*
|
|
3941
4447
|
* ### Example
|
|
@@ -3951,34 +4457,16 @@ type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must
|
|
|
3951
4457
|
*
|
|
3952
4458
|
* const SyncResponse = result(
|
|
3953
4459
|
* object({ timestamp: NonNegativeInt }),
|
|
3954
|
-
* typed("
|
|
4460
|
+
* typed("SyncFailed", { message: String }),
|
|
3955
4461
|
* );
|
|
3956
4462
|
*
|
|
3957
|
-
* const
|
|
3958
|
-
*
|
|
3959
|
-
*
|
|
3960
|
-
*
|
|
3961
|
-
* const response = validated.value;
|
|
3962
|
-
* return response.ok
|
|
3963
|
-
* ? `Synced at ${response.value.timestamp}`
|
|
3964
|
-
* : response.error.message;
|
|
3965
|
-
* };
|
|
4463
|
+
* const validated = SyncResponse.fromUnknown({
|
|
4464
|
+
* ok: true,
|
|
4465
|
+
* value: { timestamp: 42 },
|
|
4466
|
+
* });
|
|
3966
4467
|
*
|
|
3967
|
-
*
|
|
3968
|
-
*
|
|
3969
|
-
* ok: true,
|
|
3970
|
-
* value: { timestamp: 42 },
|
|
3971
|
-
* }),
|
|
3972
|
-
* ).toBe("Synced at 42");
|
|
3973
|
-
* expect(
|
|
3974
|
-
* describeResponse({
|
|
3975
|
-
* ok: false,
|
|
3976
|
-
* error: { type: "SyncError", message: "Offline" },
|
|
3977
|
-
* }),
|
|
3978
|
-
* ).toBe("Offline");
|
|
3979
|
-
* expect(describeResponse({ ok: true, value: { timestamp: -1 } })).toBe(
|
|
3980
|
-
* "Invalid response",
|
|
3981
|
-
* );
|
|
4468
|
+
* expectOk(validated, { ok: true, value: { timestamp: 42 } });
|
|
4469
|
+
* expectOk(validated.value, { timestamp: 42 });
|
|
3982
4470
|
* ```
|
|
3983
4471
|
*
|
|
3984
4472
|
* @group Results
|
|
@@ -4010,7 +4498,7 @@ export declare const UnknownResult: DiscriminatedUnionType<"ok", readonly [Stric
|
|
|
4010
4498
|
}>]>;
|
|
4011
4499
|
export type UnknownResult = typeof UnknownResult.Output;
|
|
4012
4500
|
/**
|
|
4013
|
-
*
|
|
4501
|
+
* Creates an {@link ObjectType} with a literal `type` property.
|
|
4014
4502
|
*
|
|
4015
4503
|
* The discriminator belongs to `typed`, so additional properties cannot declare
|
|
4016
4504
|
* `type`. The discriminator Input is `string`, inherited from {@link String},
|
|
@@ -4022,35 +4510,38 @@ export type UnknownResult = typeof UnknownResult.Output;
|
|
|
4022
4510
|
* ### Example
|
|
4023
4511
|
*
|
|
4024
4512
|
* ```ts
|
|
4025
|
-
* import { String,
|
|
4513
|
+
* import { String, typed } from "@evolu/common";
|
|
4026
4514
|
*
|
|
4027
4515
|
* const Pending = typed("Pending", {
|
|
4028
4516
|
* label: String,
|
|
4029
4517
|
* });
|
|
4030
4518
|
*
|
|
4031
|
-
*
|
|
4032
|
-
* const Status = discriminatedUnion(Pending, Completed);
|
|
4033
|
-
*
|
|
4034
|
-
* expectOk(Status.fromUnknown({ type: "Pending", label: "Waiting" }), {
|
|
4519
|
+
* expectOk(Pending.fromUnknown({ type: "Pending", label: "Waiting" }), {
|
|
4035
4520
|
* type: "Pending",
|
|
4036
4521
|
* label: "Waiting",
|
|
4037
4522
|
* });
|
|
4038
|
-
* expectOk(Status.fromUnknown({ type: "Completed" }), {
|
|
4039
|
-
* type: "Completed",
|
|
4040
|
-
* });
|
|
4041
4523
|
* ```
|
|
4042
4524
|
*
|
|
4043
4525
|
* @group Discriminated unions
|
|
4044
4526
|
*/
|
|
4045
4527
|
export declare function typed<const Tag extends TypeName>(tag: ValidateTypedTag<Tag>): TypedType<Tag>;
|
|
4528
|
+
/** Creates a Tagged Object Type with declared properties. */
|
|
4046
4529
|
export declare function typed<const Tag extends TypeName, const Props extends ObjectProps>(tag: ValidateTypedTag<Tag>, props: Props, ...validation: [TypedValidationError<Props>] extends [never] ? [] : [ValidationFailure<TypedValidationError<Props>>]): TypedType<Tag, Props>;
|
|
4530
|
+
/** Creates a Tagged Object Type with additional record properties. */
|
|
4047
4531
|
export declare function typed<const Tag extends TypeName, const Props extends ObjectProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(tag: ValidateTypedTag<Tag>, props: Props, record: Rest, ...validation: [
|
|
4048
4532
|
TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>
|
|
4049
4533
|
] extends [never] ? [] : [
|
|
4050
4534
|
ValidationFailure<TypedValidationError<Props> | ObjectRecordValidationError<TypedProps<Tag, Props>, Rest>>
|
|
4051
4535
|
]): TypedType<Tag, Props, Rest extends ObjectRecordTypeNode ? Rest : never>;
|
|
4052
4536
|
/**
|
|
4053
|
-
* A
|
|
4537
|
+
* A TypeScript interface with a literal `type` property.
|
|
4538
|
+
*
|
|
4539
|
+
* Use `Typed` for both domain objects in discriminated unions and plain domain
|
|
4540
|
+
* errors returned by {@link Result}. Name a domain error interface `XError`.
|
|
4541
|
+
* When `X` already describes a failure, use `X` for its `type` discriminant
|
|
4542
|
+
* because `Error` describes the interface's role rather than the runtime error
|
|
4543
|
+
* kind. Keep `Error` when it is needed to make the discriminant unambiguous,
|
|
4544
|
+
* such as `TimeoutError`.
|
|
4054
4545
|
*
|
|
4055
4546
|
* Typed unions model mutually exclusive states as separate variants instead of
|
|
4056
4547
|
* combinations of flags and optional properties. TypeScript narrows a union by
|
|
@@ -4061,20 +4552,23 @@ export declare function typed<const Tag extends TypeName, const Props extends Ob
|
|
|
4061
4552
|
* ### Example
|
|
4062
4553
|
*
|
|
4063
4554
|
* ```ts
|
|
4064
|
-
* import { type Typed } from "@evolu/common";
|
|
4555
|
+
* import { err, ok, type Result, type Typed } from "@evolu/common";
|
|
4556
|
+
*
|
|
4557
|
+
* interface User extends Typed<"User"> {
|
|
4558
|
+
* readonly id: string;
|
|
4559
|
+
* }
|
|
4065
4560
|
*
|
|
4066
|
-
*
|
|
4561
|
+
* const getUser = (id: string): Result<User, UserNotFoundError> =>
|
|
4562
|
+
* id === "user-1"
|
|
4563
|
+
* ? ok({ type: "User", id })
|
|
4564
|
+
* : err({ type: "UserNotFound", id });
|
|
4067
4565
|
*
|
|
4068
|
-
*
|
|
4069
|
-
*
|
|
4070
|
-
*
|
|
4071
|
-
* return "Waiting";
|
|
4072
|
-
* case "Completed":
|
|
4073
|
-
* return "Done";
|
|
4074
|
-
* }
|
|
4075
|
-
* };
|
|
4566
|
+
* interface UserNotFoundError extends Typed<"UserNotFound"> {
|
|
4567
|
+
* readonly id: string;
|
|
4568
|
+
* }
|
|
4076
4569
|
*
|
|
4077
|
-
*
|
|
4570
|
+
* expectOk(getUser("user-1"), { type: "User", id: "user-1" });
|
|
4571
|
+
* expectErr(getUser("missing"), { type: "UserNotFound", id: "missing" });
|
|
4078
4572
|
* ```
|
|
4079
4573
|
*
|
|
4080
4574
|
* @group Discriminated unions
|
|
@@ -4085,9 +4579,8 @@ export interface Typed<Tag extends TypeName> {
|
|
|
4085
4579
|
/**
|
|
4086
4580
|
* Extracts members of a {@link Typed} Output union by their `type` literal.
|
|
4087
4581
|
*
|
|
4088
|
-
* The requested
|
|
4089
|
-
* so a misspelling is a TypeScript error instead of silently producing
|
|
4090
|
-
* `never`.
|
|
4582
|
+
* The requested tag is constrained to the union's actual discriminator values,
|
|
4583
|
+
* so a misspelling is a TypeScript error instead of silently producing `never`.
|
|
4091
4584
|
*
|
|
4092
4585
|
* ### Example
|
|
4093
4586
|
*
|
|
@@ -4131,7 +4624,8 @@ type ConcreteTypedTagError = CompileTimeError<"Type", "Tag must be one concrete
|
|
|
4131
4624
|
type TypedValidationError<Props extends ObjectProps> = "type" extends keyof Props ? TypedTypePropertyError : ObjectValidationError<Props>;
|
|
4132
4625
|
type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties must not declare the reserved "type" property.'>;
|
|
4133
4626
|
/**
|
|
4134
|
-
*
|
|
4627
|
+
* Creates a {@link Type} for producer Results with value, error, or done
|
|
4628
|
+
* outcomes.
|
|
4135
4629
|
*
|
|
4136
4630
|
* The three outcomes are `Ok<Value>`, `Err<Error>`, and `Err<Typed<"Done"> & {
|
|
4137
4631
|
* done: Done }>`. This keeps normal completion distinct from failure while
|
|
@@ -4144,7 +4638,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
|
|
|
4144
4638
|
*
|
|
4145
4639
|
* const StringNextResult = nextResult(
|
|
4146
4640
|
* String,
|
|
4147
|
-
* typed("
|
|
4641
|
+
* typed("ReadFailed", { message: String }),
|
|
4148
4642
|
* String,
|
|
4149
4643
|
* );
|
|
4150
4644
|
*
|
|
@@ -4168,7 +4662,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
|
|
|
4168
4662
|
* expect(
|
|
4169
4663
|
* describeNext({
|
|
4170
4664
|
* ok: false,
|
|
4171
|
-
* error: { type: "
|
|
4665
|
+
* error: { type: "ReadFailed", message: "Offline" },
|
|
4172
4666
|
* }),
|
|
4173
4667
|
* ).toBe("Error: Offline");
|
|
4174
4668
|
* ```
|
|
@@ -4200,7 +4694,7 @@ export declare const UnknownNextResult: DiscriminatedUnionType<"ok", readonly [S
|
|
|
4200
4694
|
}>]>;
|
|
4201
4695
|
export type UnknownNextResult = typeof UnknownNextResult.Output;
|
|
4202
4696
|
/**
|
|
4203
|
-
* Discriminated
|
|
4697
|
+
* Discriminated union {@link Type}.
|
|
4204
4698
|
*
|
|
4205
4699
|
* With no explicit key, the conventional `type` property created by
|
|
4206
4700
|
* {@link typed} is used. Pass a key first to discriminate
|
|
@@ -4231,6 +4725,34 @@ export type UnknownNextResult = typeof UnknownNextResult.Output;
|
|
|
4231
4725
|
* @group Discriminated unions
|
|
4232
4726
|
*/
|
|
4233
4727
|
export declare function discriminatedUnion<const Members extends DiscriminatedUnionMembers>(...members: Members & DiscriminatedUnionValidation<"type", Members>): DiscriminatedUnionType<"type", Members>;
|
|
4728
|
+
/**
|
|
4729
|
+
* Creates a Discriminated Union Type with an explicit discriminator key.
|
|
4730
|
+
*
|
|
4731
|
+
* ### Example
|
|
4732
|
+
*
|
|
4733
|
+
* ```ts
|
|
4734
|
+
* import {
|
|
4735
|
+
* Number,
|
|
4736
|
+
* String,
|
|
4737
|
+
* discriminatedUnion,
|
|
4738
|
+
* literal,
|
|
4739
|
+
* object,
|
|
4740
|
+
* } from "@evolu/common";
|
|
4741
|
+
*
|
|
4742
|
+
* const Added = object({ kind: literal("added"), value: String });
|
|
4743
|
+
* const Removed = object({ kind: literal("removed"), id: Number });
|
|
4744
|
+
* const Event = discriminatedUnion("kind", Added, Removed);
|
|
4745
|
+
*
|
|
4746
|
+
* expectOk(Event.fromUnknown({ kind: "added", value: "Evolu" }), {
|
|
4747
|
+
* kind: "added",
|
|
4748
|
+
* value: "Evolu",
|
|
4749
|
+
* });
|
|
4750
|
+
* expectOk(Event.fromUnknown({ kind: "removed", id: 1 }), {
|
|
4751
|
+
* kind: "removed",
|
|
4752
|
+
* id: 1,
|
|
4753
|
+
* });
|
|
4754
|
+
* ```
|
|
4755
|
+
*/
|
|
4234
4756
|
export declare function discriminatedUnion<const Key extends string, const Members extends DiscriminatedUnionMembers>(key: ValidateDiscriminatedUnionKey<Key>, ...members: Members & DiscriminatedUnionValidation<Key, Members>): DiscriminatedUnionType<Key, Members>;
|
|
4235
4757
|
/**
|
|
4236
4758
|
* The routed {@link Type} returned by {@link discriminatedUnion}.
|
|
@@ -4353,10 +4875,10 @@ type DiscriminatedUnionMemberConcreteTypeError = CompileTimeError<"Type", "Membe
|
|
|
4353
4875
|
type DiscriminatedUnionPropertyError<Key extends string> = CompileTimeError<"Type", `Property "${Key}" must be a required String, Number, BigInt, or Boolean Literal Type in every member.`>;
|
|
4354
4876
|
type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends DiscriminatedUnionLiteral> = CompileTimeError<"Type", `Duplicate value "${Expected}" at property "${Key}".`>;
|
|
4355
4877
|
/**
|
|
4356
|
-
*
|
|
4878
|
+
* Creates a lazy {@link Type} for recursive definitions.
|
|
4357
4879
|
*
|
|
4358
|
-
*
|
|
4359
|
-
* trees and mutually recursive models.
|
|
4880
|
+
* The definition is evaluated on first use and then cached, allowing recursive
|
|
4881
|
+
* data such as trees and mutually recursive models.
|
|
4360
4882
|
*
|
|
4361
4883
|
* A recursive declaration refers to its own variable while that variable is
|
|
4362
4884
|
* being initialized, so TypeScript cannot infer it reliably. Getter-based
|
|
@@ -4376,12 +4898,10 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
|
|
|
4376
4898
|
*
|
|
4377
4899
|
* ```ts
|
|
4378
4900
|
* import {
|
|
4379
|
-
* Number,
|
|
4380
4901
|
* String,
|
|
4381
4902
|
* array,
|
|
4382
4903
|
* lazy,
|
|
4383
4904
|
* object,
|
|
4384
|
-
* optional,
|
|
4385
4905
|
* type ArrayError,
|
|
4386
4906
|
* type LazyType,
|
|
4387
4907
|
* type ObjectError,
|
|
@@ -4402,35 +4922,19 @@ type DiscriminatedUnionDuplicateValueError<Key extends string, Expected extends
|
|
|
4402
4922
|
* () => object({ value: String, children: array(Tree) }),
|
|
4403
4923
|
* );
|
|
4404
4924
|
*
|
|
4405
|
-
*
|
|
4406
|
-
*
|
|
4407
|
-
*
|
|
4408
|
-
* }
|
|
4409
|
-
*
|
|
4410
|
-
* interface Right {
|
|
4411
|
-
* readonly count: number;
|
|
4412
|
-
* readonly left?: Left;
|
|
4413
|
-
* }
|
|
4414
|
-
*
|
|
4415
|
-
* interface LeftError extends ObjectError<{
|
|
4416
|
-
* readonly label: TypeOfError<"String">;
|
|
4417
|
-
* readonly right?: RightError;
|
|
4418
|
-
* }> {}
|
|
4419
|
-
*
|
|
4420
|
-
* interface RightError extends ObjectError<{
|
|
4421
|
-
* readonly count: TypeOfError<"Number">;
|
|
4422
|
-
* readonly left?: LeftError;
|
|
4423
|
-
* }> {}
|
|
4424
|
-
*
|
|
4425
|
-
* const Left: LazyType<Left, Left, never, LeftError, LeftError> = lazy(
|
|
4426
|
-
* () => object({ label: String, right: optional(Right) }),
|
|
4427
|
-
* );
|
|
4925
|
+
* const result = Tree.fromUnknown({
|
|
4926
|
+
* value: "root",
|
|
4927
|
+
* children: [{ value: "leaf", children: [] }],
|
|
4928
|
+
* });
|
|
4428
4929
|
*
|
|
4429
|
-
*
|
|
4430
|
-
*
|
|
4930
|
+
* expectOk(result, {
|
|
4931
|
+
* value: "root",
|
|
4932
|
+
* children: [{ value: "leaf", children: [] }],
|
|
4933
|
+
* });
|
|
4934
|
+
* expectTypeOf(result.value).toEqualTypeOf<Tree>();
|
|
4431
4935
|
* ```
|
|
4432
4936
|
*
|
|
4433
|
-
* @group Recursive
|
|
4937
|
+
* @group Recursive
|
|
4434
4938
|
*/
|
|
4435
4939
|
export declare function lazy<Target extends ConcreteTypeNode>(getType: Thunk<ValidateLazyTarget<Target>>): LazyType<Target["Input"], Target["Output"], TypeFromError<Target>, InferErrors<RootType<Target>>, InferErrors<Target>, CanonicalInputOf<Target>, IdentityEncodingOf<Target>>;
|
|
4436
4940
|
/**
|
|
@@ -4448,7 +4952,7 @@ export declare function lazy<Target extends ConcreteTypeNode>(getType: Thunk<Val
|
|
|
4448
4952
|
* recursive declaration finite for TypeScript while preserving structured
|
|
4449
4953
|
* errors at every boundary.
|
|
4450
4954
|
*
|
|
4451
|
-
* @group Recursive
|
|
4955
|
+
* @group Recursive
|
|
4452
4956
|
*/
|
|
4453
4957
|
export interface LazyType<in out Input, in out Output, in out FromError extends TypeError, in out InputError extends TypeError, in out Errors extends TypeError, in out CanonicalInput extends Input = Input, in out UsesIdentityEncoding extends boolean = true> extends Type<"Lazy", Input, Output, FromError, Type<"Lazy", Input, Input, InputError, null, InputError, never, Input>, Errors, never, CanonicalInput, UsesIdentityEncoding> {
|
|
4454
4958
|
readonly [lazyTypeSymbol]: true;
|
|
@@ -4504,7 +5008,7 @@ export interface JsonObject {
|
|
|
4504
5008
|
readonly [key: string]: JsonValue;
|
|
4505
5009
|
}
|
|
4506
5010
|
/**
|
|
4507
|
-
* One issue found while validating an exact {@link JsonValue}.
|
|
5011
|
+
* One issue found while validating a candidate as an exact {@link JsonValue}.
|
|
4508
5012
|
*
|
|
4509
5013
|
* @group JSON
|
|
4510
5014
|
*/
|
|
@@ -4542,7 +5046,8 @@ export type JsonValueIssue = {
|
|
|
4542
5046
|
readonly ancestorPath: ReadonlyArray<string | number | symbol>;
|
|
4543
5047
|
};
|
|
4544
5048
|
/**
|
|
4545
|
-
* An error containing one or more issues found
|
|
5049
|
+
* An error containing one or more issues found while validating a candidate as
|
|
5050
|
+
* an exact {@link JsonValue}.
|
|
4546
5051
|
*
|
|
4547
5052
|
* @group JSON
|
|
4548
5053
|
*/
|
|
@@ -4580,6 +5085,21 @@ export interface JsonError extends TypeError<"Json"> {
|
|
|
4580
5085
|
/**
|
|
4581
5086
|
* Exact root Type for {@link JsonValue} data trees.
|
|
4582
5087
|
*
|
|
5088
|
+
* ### Example
|
|
5089
|
+
*
|
|
5090
|
+
* ```ts
|
|
5091
|
+
* import { JsonValue, type JsonValueInput } from "@evolu/common";
|
|
5092
|
+
*
|
|
5093
|
+
* const input: JsonValueInput = {
|
|
5094
|
+
* name: "Ada",
|
|
5095
|
+
* scores: [10, 20],
|
|
5096
|
+
* };
|
|
5097
|
+
* const result = JsonValue.fromUnknown(input);
|
|
5098
|
+
*
|
|
5099
|
+
* expectOk(result, input);
|
|
5100
|
+
* expectTypeOf(result.value).toEqualTypeOf<JsonValue>();
|
|
5101
|
+
* ```
|
|
5102
|
+
*
|
|
4583
5103
|
* @group JSON
|
|
4584
5104
|
*/
|
|
4585
5105
|
export declare const JsonValue: JsonValueType;
|
|
@@ -4609,21 +5129,52 @@ export type Json = typeof Json.Output;
|
|
|
4609
5129
|
/**
|
|
4610
5130
|
* Totally parses proven {@link Json} text into an exact {@link JsonValue}.
|
|
4611
5131
|
*
|
|
5132
|
+
* ### Example
|
|
5133
|
+
*
|
|
5134
|
+
* ```ts
|
|
5135
|
+
* import { Json, jsonToJsonValue } from "@evolu/common";
|
|
5136
|
+
*
|
|
5137
|
+
* const value = jsonToJsonValue(Json.orThrow('{"name":"Ada"}'));
|
|
5138
|
+
*
|
|
5139
|
+
* expect(value).toEqual({ name: "Ada" });
|
|
5140
|
+
* ```
|
|
5141
|
+
*
|
|
4612
5142
|
* @group JSON
|
|
4613
5143
|
*/
|
|
4614
5144
|
export declare const jsonToJsonValue: (value: Json) => JsonValue;
|
|
4615
5145
|
/**
|
|
4616
5146
|
* Totally encodes an exact {@link JsonValue} as canonical {@link Json} text.
|
|
4617
5147
|
*
|
|
5148
|
+
* ### Example
|
|
5149
|
+
*
|
|
5150
|
+
* ```ts
|
|
5151
|
+
* import { jsonValueToJson, type JsonValue } from "@evolu/common";
|
|
5152
|
+
*
|
|
5153
|
+
* const value: JsonValue = { name: "Ada" };
|
|
5154
|
+
*
|
|
5155
|
+
* expect(jsonValueToJson(value)).toBe('{"name":"Ada"}');
|
|
5156
|
+
* ```
|
|
5157
|
+
*
|
|
4618
5158
|
* @group JSON
|
|
4619
5159
|
*/
|
|
4620
5160
|
export declare const jsonValueToJson: (value: JsonValue) => Json;
|
|
4621
5161
|
/**
|
|
4622
|
-
* {@link Json}
|
|
5162
|
+
* Transformation {@link Type} that parses {@link Json} into {@link JsonValue}.
|
|
4623
5163
|
*
|
|
4624
5164
|
* Decoding unknown input first validates the Json Brand. Starting from the
|
|
4625
5165
|
* typed Json parent is infallible. Encoding canonicalizes JSON text.
|
|
4626
5166
|
*
|
|
5167
|
+
* ### Example
|
|
5168
|
+
*
|
|
5169
|
+
* ```ts
|
|
5170
|
+
* import { JsonValueFromJson } from "@evolu/common";
|
|
5171
|
+
*
|
|
5172
|
+
* const result = JsonValueFromJson.fromUnknown('{ "name": "Ada" }');
|
|
5173
|
+
*
|
|
5174
|
+
* expectOk(result, { name: "Ada" });
|
|
5175
|
+
* expect(JsonValueFromJson.to(result.value)).toBe('{"name":"Ada"}');
|
|
5176
|
+
* ```
|
|
5177
|
+
*
|
|
4627
5178
|
* @group JSON
|
|
4628
5179
|
*/
|
|
4629
5180
|
export declare const JsonValueFromJson: TransformType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "Json", JsonError>, JsonValueType, "JsonValueFromJson", never, string & Brand<"Json">>;
|