API Reference / @evolu/common / Type / RecursiveType
Interface: RecursiveType<ParentType>
Defined in: packages/common/src/Type.ts:3059
🧩 Validation, Parsing, and Transformation
Evolu Type
is:
- A TypeScript type with a Brand whenever it's possible.
- A function to create a value of that type, which may fail.
- A function to transform value back to its original representation, which cannot fail.
Types are chainable. The chain starts with a Base Type that refines an
unknown value into something and can continue with further refinements or
transformations. For example, NonEmptyTrimmedString100
chain looks like
this:
Unknown
-> String
-> TrimmedString
-> NonEmptyTrimmedString100
For NonEmptyTrimmedString100
, the parent Type is TrimmedString
. For
TrimmedString
, the parent Type is String
.
The parent of the String
Type is the String
Type itself. All Base Types
fromParent
functions are just a typed alias to fromUnknown
to ensure that
fromParent
and toParent
can be called on any Type.
Speaking of fromParent
and toParent
, those functions exist to bypass
parent Types when we can rely on TypeScript types.
Type
transformations should be reversible. If you need an irreversible
transformation, such as TrimString
(trimming is not reversible as untrim
can't know what has been trimmed), you can do that, but note in JSDoc that
to
will not restore the original representation. You can also use
assert: assert(false, "Untrim is not possible")
.
Tip
If necessary, write globalThis.String
instead of String
to avoid naming
clashes with Base Types.
Design Decision:
While the from
function can fail, the to
function cannot. This simplifies
the model by ensuring that every valid input has a corresponding valid
output, eliminating the risk of edge cases caused by irreversible
operations.
// TODO: Links to examples.
Extends
Type
<"Recursive"
,InferType
<ParentType
>,InferInput
<ParentType
>,InferError
<ParentType
>,InferParent
<ParentType
>,InferParentError
<ParentType
>>
Type Parameters
Type Parameter |
---|
ParentType extends AnyType |
Properties
Property | Modifier | Type | Description | Inherited from | Defined in |
---|---|---|---|---|---|
[EvoluTypeSymbol] | readonly | true | - | Type .[EvoluTypeSymbol] | packages/common/src/Type.ts:171 |
Error | public | InferError <ParentType > | The specific error introduced by this Type. ### Example type StringError = typeof String.Error; | Type .Error | packages/common/src/Type.ts:96 |
Errors | readonly | | InferError <ParentType > | InferParentError <ParentType > | Error | ParentError ### Example type StringParentErrors = typeof String.Errors; | Type .Errors |
from | readonly | (value ) => Result <InferType <ParentType >, | InferError <ParentType > | InferParentError <ParentType >> | Creates T from an Input value. This is useful when we have a typed value. from is a typed alias of fromUnknown . | Type .from | packages/common/src/Type.ts:111 |
fromParent | readonly | (value ) => Result <InferType <ParentType >, InferError <ParentType >> | Creates T from Parent type. This function skips parent Types validations/transformations when we have already partially validated/transformed value. For example, TrimString.from checks whether a value is a string and trims it. If we only want to trim a string, we can use fromParent . ### Example // string & Brand<"Trimmed"> const value = TrimString.fromParent("a ").value; // as efficient as foo.trim() | Type .fromParent | packages/common/src/Type.ts:145 |
fromUnknown | readonly | (value ) => Result <InferType <ParentType >, | InferError <ParentType > | InferParentError <ParentType >> | Creates T from an unknown value. This is useful when a value is unknown. | Type .fromUnknown | packages/common/src/Type.ts:118 |
Input | public | InferInput <ParentType > | The type expected by from and fromUnknown . ### Example type StringInput = typeof String.Input; | Type .Input | packages/common/src/Type.ts:94 |
is | readonly | (value ) => value is InferType<ParentType> | A type guard that checks whether an unknown value satisfies the Type. ### Example const value: unknown = "hello"; if (String.is(value)) { // TypeScript now knows valueis a string here. console.log("This is a valid string!"); } const strings: unknown[] = [1, "hello", true, "world"]; const filteredStrings = strings.filter(String.is); console.log(filteredStrings); // ["hello", "world"] | Type .is | packages/common/src/Type.ts:169 |
name | readonly | "Recursive" | - | Type .name | packages/common/src/Type.ts:102 |
Parent | public | InferParent <ParentType > | The parent type. ### Example type StringParent = typeof String.Parent; | Type .Parent | packages/common/src/Type.ts:98 |
ParentError | public | InferParentError <ParentType > | The parent's error. ### Example type StringParentError = typeof String.ParentError; | Type .ParentError | packages/common/src/Type.ts:100 |
to | readonly | (value ) => InferInput | The opposite of from and fromUnknown . This is useful to transform T back to its Input representation. For refine , it only removes the brand. For transform , it changes value. | Type .to | packages/common/src/Type.ts:127 |
toParent | readonly | (value ) => InferParent | The opposite of fromParent . | Type .toParent | packages/common/src/Type.ts:148 |
Type | readonly | InferType | The type this Type resolves to. ### Example type String = typeof String.Type; | Type .Type | packages/common/src/Type.ts:182 |
Methods
getParentType()
getParentType(): ParentType;
Defined in: packages/common/src/Type.ts:3068
Returns
ParentType