API reference › @evolu/common › Type › transform
Call Signature
function transform<Name, ParentType, OutputType, ToOutput>(
name: ValidateChildTypeName<Name, ParentType>,
parent: ValidateParent<ParentType>,
output: ValidateOutput<OutputType>,
operations: {
from: (value: ParentType["Output"]) => Result<OutputType["Input"], never>;
to: (value: CanonicalInputOf<OutputType>) => ToOutput;
},
): TransformType<ParentType, OutputType, Name, never, ToOutput>;
Defined in: packages/common/src/Type.ts:2277
Transform Type.
from accepts the semantic Output. from.parent converts the parent Output
to the output Type Input, then runs the complete output Type pipeline. to
canonically encodes every output Type value before converting it back through
the parent Type.
The callbacks must form a lawful codec: decoding to(output) must reproduce
the same semantic Output for every valid output value. Encoding may
canonicalize multiple parent representations, but it must be total and must
not lose distinctions present in the Output domain.
Transformation callbacks are Type construction code. Their successful results
are asserted against the declared boundary so a broken callback fails as a
developer error rather than becoming a validation error. Like all
Type-construction callbacks, they are trusted to follow their declared
TypeScript types. A Result<_, never> callback is therefore trusted never to
return an Err.
Errors from the parent and the forward callback remain unchanged. A forward
callback error must use the transformation name as its type. Errors from the
output Type are nested in a TransformOutputError so formatting can be
delegated to that particular Type, so outputError is reserved for that
wrapper. When the forward callback is fallible, the final formatter argument
formats only that callback's own errors. Parent and output Type errors use
their respective formatters automatically.
Example
import {
assertEqual,
assertOk,
Boolean,
literal,
ok,
transform,
union,
} from "@evolu/common";
const BooleanString = union(literal("false"), literal("true"));
const BooleanFromString = transform(
"BooleanFromString",
BooleanString,
Boolean,
{
from: (value) => ok(value === "true"),
to: (value) => (value ? "true" : "false"),
},
);
assertOk(BooleanFromString.from.parent("true"), true);
assertEqual(BooleanFromString.to(false), "false");
Call Signature
function transform<Name, ParentType, OutputType, ToOutput, FromError>(
name: ValidateChildTypeName<Name, ParentType>,
parent: ValidateParent<ParentType>,
output: ValidateOutput<OutputType>,
operations: {
from: (
value: ParentType["Output"],
) => Result<OutputType["Input"], FromError>;
to: (value: CanonicalInputOf<OutputType>) => ToOutput;
},
formatError: [FromError] extends [never]
? never
: TypeErrorFormatter<NoInfer>,
): TransformType<ParentType, OutputType, Name, FromError, ToOutput>;
Defined in: packages/common/src/Type.ts:2349
Creates a fallible transformed Type with its own error formatter.
Example
import {
assertEqual,
assertType,
Data,
assertErr,
assertOk,
Boolean,
String,
err,
ok,
transform,
type Result,
type TypeError,
} from "@evolu/common";
interface BooleanFromStringError extends TypeError<"BooleanFromString"> {
readonly value: string;
}
const BooleanFromString = transform(
"BooleanFromString",
String,
Boolean,
{
from: (value): Result<boolean, BooleanFromStringError> =>
value === "true"
? ok(true)
: value === "false"
? ok(false)
: err({ type: "BooleanFromString", value }),
to: (value) => (value ? "true" : "false"),
},
() => 'Expected "true" or "false".',
);
assertOk(BooleanFromString.fromUnknown("true"), true);
assertEqual(BooleanFromString.to(false), "false");
const invalid = BooleanFromString.fromUnknown("yes");
assertErr(invalid);
assertType(Data, invalid.error);
assertEqual(invalid.error, { type: "BooleanFromString", value: "yes" });
assertEqual(
BooleanFromString.formatError(invalid.error),
'Expected "true" or "false".',
);