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:2141

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.

Use createTypeWithError to wrap an existing validator's errors.

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:2153

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:2176

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