API reference@evolu/commonType › createType

Call Signature

function createType<Name, Output, Error>(
  name: ValidateConcreteTypeName<Name>,
  fromUnknown: (value: unknown) => Result<Output, Error>,
  formatError: TypeErrorFormatter<NoInfer>,
): Type<Name, Output, Output, Error, null, Error, never, Output>;

Defined in: packages/common/src/Type.ts:1972

Custom Type.

createType is refinement-only. Use transform to change a value's representation. On success, a validation callback must return the value it received, narrowed to its output type, rather than a replacement value. This includes replacements assignable to the same TypeScript type. The identity-preserving contract is asserted at runtime. It lets structural Types preserve their input values and makes encoding an identity step.

Like all Type-construction callbacks, validation callbacks are trusted to follow their declared TypeScript types. A Result<_, never> callback is therefore trusted never to return an Err.

An infallible child accepts every parent Output, so its Output remains the parent Output. A fallible child can narrow that Output but cannot change its representation.

A root formatter handles the root validation error. A child formatter handles only the error introduced by that child; inherited errors are formatted by the parent Type automatically. A fallible child must have one concrete name; its error's type must equal that name and must not duplicate an inherited error type. An infallible child has no own error to format.

Example

A root Type for a custom external value category:

import {
  assertEqual,
  assertErr,
  assertOk,
  assertType,
  createType,
  Data,
  err,
  ok,
  type Result,
  type TypeError,
} from "@evolu/common";

interface TextError extends TypeError<"Text"> {
  readonly value: unknown;
}

const Text = createType(
  "Text",
  (value): Result<string, TextError> =>
    typeof value === "string" ? ok(value) : err({ type: "Text", value }),
  () => "Expected text.",
);

assertOk(Text.fromUnknown("Evolu"), "Evolu");
const invalid = Text.fromUnknown(42);
assertErr(invalid);
assertType(Data, invalid.error);
assertEqual(invalid.error, { type: "Text", value: 42 });

Call Signature

function createType<Name, ParentType>(
  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>
>;

Defined in: packages/common/src/Type.ts:1984

Creates an infallible child Type that preserves its parent's Output.

Call Signature

function createType<Name, ParentType, Output, Error>(
  name: Name,
  parent: ValidateBrandParent<Name, ParentType>,
  fromParent: (value: ParentType["Output"]) => Result<Output, Error>,
  formatError: [Error] extends [never] ? never : TypeErrorFormatter<NoInfer>,
): Type<
  Name,
  ParentType["Input"],
  Output,
  Error,
  ParentType,
  Error | InferErrors<ParentType>,
  ChildCustomFrom<ParentType, Output, Error>,
  CanonicalInputForChild<ParentType, Output>,
  IdentityEncodingOf<ParentType>
>;

Defined in: packages/common/src/Type.ts:2007

Creates a fallible child Type that narrows its parent's Output.