[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [Type](https://evolu.dev/docs/api-reference/common/Type) › OptionalType

Defined in: [packages/common/src/Type.ts:4362](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L4362)

Evolu [Type](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type) is like a type guard that returns typed errors (via
[Result](https://evolu.dev/docs/api-reference/common/Result/type-aliases/Result)) instead of throwing. We either receive a safely typed value or
a composable typed error that tells us exactly why the validation failed.

The reason why Evolu Type exists is that no other TypeScript validation
library met Evolu's requirements. A distinctive feature of Evolu Type
compared to other validation libraries is that it returns typed errors rather
than string messages. This allows TypeScript to enforce that all validation
errors are handled via [exhaustiveCheck](https://evolu.dev/docs/api-reference/common/Function/functions/exhaustiveCheck), significantly improving the
developer experience. Those requirements are:

- **Result-based error handling** – no exceptions for normal control flow.
- **Typed errors with decoupled formatters** – validation logic ≠ user
  messages.
- **Consistent constraints via [Brand](https://evolu.dev/docs/api-reference/common/Brand/interfaces/Brand)** – every constraint becomes part
  of the type.
- **Skippable validation** – parent validations can be skipped when already
  proved by types.
- **Simple, top-down implementation** – readable source code from top to
  bottom.
- **No user-land chaining DSL** – prepared for TC39 Hack pipes.

Evolu Type supports [Standard Schema](https://standardschema.dev/) for
interoperability with 40+ validation-compatible tools and frameworks.

## Base Types

```ts
// Validate unknown values
const value: unknown = "hello";
const stringResult = String.fromUnknown(value);
if (!stringResult.ok) {
  // console.error(formatStringError(stringResult.error));
  return stringResult;
}
// Safe branch: value is now string
const upper = stringResult.value.toUpperCase();

// Type guard style
if (String.is(value)) {
  // narrowed to string
}

// Composing: arrays & objects
const Numbers = array(Number); // ReadonlyArray<number>
const Point = object({ x: Number, y: Number });

Numbers.from([1, 2, 3]); // ok
Point.from({ x: 1, y: 2 }); // ok
Point.from({ x: 1, y: "2" }); // err -> nested Number error
```

## Branded types

Branding is the recommended way to define types in Evolu. Instead of using
primitive types like `string` or `number` directly, wrap them with
[brand](https://evolu.dev/docs/api-reference/common/Type/functions/brand) to create semantically meaningful types. See [Brand](https://evolu.dev/docs/api-reference/common/Brand/interfaces/Brand) for
why this matters.

```ts
const CurrencyCode = brand("CurrencyCode", String, (value) =>
  /^[A-Z]{3}$/.test(value)
    ? ok(value)
    : err<CurrencyCodeError>({ type: "CurrencyCode", value }),
);
type CurrencyCode = typeof CurrencyCode.Type; // string & Brand<"CurrencyCode">

interface CurrencyCodeError extends TypeError<"CurrencyCode"> {}

const formatCurrencyCodeError = createTypeErrorFormatter<CurrencyCodeError>(
  (error) => `Invalid currency code: ${error.value}`,
);

const r = CurrencyCode.from("USD"); // ok("USD")
const e = CurrencyCode.from("usd"); // err(...)
```

See also reusable brand factories like `minLength`, `maxLength`, `trimmed`,
`positive`, `between`, etc.

## Object types

```ts
const User = object({
  name: NonEmptyTrimmedString100,
  age: optional(PositiveInt),
});

// Use interface for objects. TypeScript displays the interface name
// instead of expanding all properties.
interface User extends InferType<typeof User> {}

User.from({ name: "Alice" }); // ok
User.from({ name: "Alice", age: -1 }); // err(PositiveInt)

// TODO: Add `record`
```

## JSON type

```ts
const Person = object({
  name: NonEmptyString50,
  // Did you know that JSON.stringify converts NaN (a number) into null?
  // To prevent this, use FiniteNumber.
  age: FiniteNumber,
});
interface Person extends InferType<typeof Person> {}

const [PersonJson, personToPersonJson, personJsonToPerson] = json(
  Person,
  "PersonJson",
);
// string & Brand<"PersonJson">
type PersonJson = typeof PersonJson.Type;

const person = Person.orThrow({
  name: "Alice",
  age: 30,
});

const personJson = personToPersonJson(person);
expect(personJsonToPerson(personJson)).toEqual(person);
```

## Error Formatting

Evolu separates validation logic from human-readable messages. There are two
layers:

1. Per-type formatters (e.g. `formatStringError`) – simple, focused, already
   used earlier in the quick start example.
2. A unified formatter via `createFormatTypeError` – composes all built-in and
   custom errors (including nested composite types) and lets us override
   selected messages.

### 1. Per-Type formatter

```ts
const r = String.fromUnknown(42);
if (!r.ok) console.error(formatStringError(r.error));
```

### 2. Unified formatter with overrides

```ts
// Override only what we care about; fall back to built-ins for the rest.
const formatTypeError = createFormatTypeError((error) => {
  if (error.type === "MinLength") return `Min length is ${error.min}`;
});

const User = object({ name: NonEmptyTrimmedString100 });
const resultUser = User.from({ name: "" });
if (!resultUser.ok) console.error(formatTypeError(resultUser.error));

const badPoint = object({ x: Number, y: Number }).from({
  x: 1,
  y: "foo",
});
if (!badPoint.ok) console.error(formatTypeError(badPoint.error));
```

The unified formatter walks nested structures (object / array / record /
tuple / union) and applies overrides only where specified, greatly reducing
boilerplate when formatting complex validation errors.

## Naming

Evolu Types intentionally use the same names as native JavaScript types
(String, Number, Boolean, etc.). When you need to distinguish between an
Evolu Type and the native type, use `globalThis` to reference the native one
(e.g., `globalThis.String`, `globalThis.Number`).

## Design decision

Evolu Type intentionally does not support bidirectional transformations. It
previously did, but supporting that while keeping typed error fidelity added
complexity that hurt readability & reliability. Most persistence pipelines
(e.g. SQLite) already require explicit mapping of query results, so implicit
reverse transforms would not buy much. We may revisit this if we can design a
minimal, 100% safe API that preserves simplicity.

## Composition without pipe

Take a look how `SimplePassword` is defined:

```ts
const SimplePassword = brand(
  "SimplePassword",
  minLength(8)(maxLength(64)(TrimmedString)),
);
```

Shallow nesting often fits one line. If it doesn't, split into named parts:

```ts
const Min8TrimmedString64 = minLength(8)(maxLength(64)(TrimmedString));
const SimplePassword = brand("SimplePassword", Min8TrimmedString64);
```

## FAQ

### How do I create a generic interface like `FooState<T>`?

TypeScript's [InferType](https://evolu.dev/docs/api-reference/common/Type/type-aliases/InferType) extracts a concrete type, not a generic one. We
cannot write `interface FooState<T> extends InferType<typeof fooState<T>>`
because `InferType` needs a concrete Type instance.

The recommended approach is to define the generic interface manually, then
create a Type factory that produces structurally compatible Types:

```ts
// Define the generic interface manually
interface FooState<T> {
  readonly value: T;
  readonly loading: boolean;
}

// Create a Type factory that produces Types matching the interface
const fooState = <T extends AnyType>(valueType: T) =>
  object({
    value: valueType,
    loading: Boolean,
  });

// Usage
const StringFooState = fooState(String);
type StringFooState = InferType<typeof StringFooState>;

// The interface and inferred type are structurally compatible
const state: FooState<string> = StringFooState.orThrow({
  value: "hi",
  loading: false,
});
```

This keeps the interface generic while having type-safe runtime validation
for each concrete use.

## Extends

- [`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type)\<`"Optional"`, [`InferType`](https://evolu.dev/docs/api-reference/common/Type/type-aliases/InferType)\<`T`\>, [`InferInput`](https://evolu.dev/docs/api-reference/common/Type/type-aliases/InferInput)\<`T`\>, [`InferError`](https://evolu.dev/docs/api-reference/common/Type/type-aliases/InferError)\<`T`\>, [`InferParent`](https://evolu.dev/docs/api-reference/common/Type/type-aliases/InferParent)\<`T`\>, [`InferParentError`](https://evolu.dev/docs/api-reference/common/Type/type-aliases/InferParentError)\<`T`\>\>

## Properties

<a id="evolutypesymbol"></a>

### \[EvoluTypeSymbol\]

```ts
readonly [EvoluTypeSymbol]: true;
```

Defined in: [packages/common/src/Type.ts:410](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L410)

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`[EvoluTypeSymbol]`](/docs/api-reference/common/Type/interfaces/Type#evolutypesymbol)

---

<a id="standard"></a>

### ~standard

```ts
readonly ~standard: Props<InferInput<T>, InferType<T>>;
```

Defined in: [packages/common/src/Type.ts:4878](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L4878)

The Standard Schema properties.

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`~standard`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#standard)

---

<a id="error"></a>

### Error

```ts
Error: InferError<T>;
```

Defined in: [packages/common/src/Type.ts:270](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L270)

The specific error introduced by this Type.

### Example

```ts
type StringError = typeof String.Error;
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`Error`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#error)

---

<a id="errors"></a>

### Errors

```ts
readonly Errors:
  | InferError<T>
| InferParentError<T>;
```

Defined in: [packages/common/src/Type.ts:474](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L474)

### Example

```ts
type StringParentErrors = typeof String.Errors;
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`Errors`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#errors)

---

<a id="from"></a>

### from

```ts
readonly from: (value: InferInput) => Result<InferType<T>,
  | InferError<T>
| InferParentError<T>>;
```

Defined in: [packages/common/src/Type.ts:285](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L285)

Creates `T` from an `Input` value.

This is useful when we have a typed value.

`from` is a typed alias of `fromUnknown`.

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`from`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#from)

---

<a id="fromparent"></a>

### fromParent

```ts
readonly fromParent: (value: InferParent) => Result<InferType<T>, InferError<T>>;
```

Defined in: [packages/common/src/Type.ts:387](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L387)

Creates `T` from `Parent` type.

This function skips parent Types validations when we have already partially
validated value.

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`fromParent`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#fromparent)

---

<a id="fromunknown"></a>

### fromUnknown

```ts
readonly fromUnknown: (value: unknown) => Result<InferType<T>,
  | InferError<T>
| InferParentError<T>>;
```

Defined in: [packages/common/src/Type.ts:379](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L379)

Creates `T` from an unknown value.

This is useful when a value is unknown.

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`fromUnknown`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#fromunknown)

---

<a id="input"></a>

### Input

```ts
Input: InferInput<T>;
```

Defined in: [packages/common/src/Type.ts:268](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L268)

The type expected by `from` and `fromUnknown`.

### Example

```ts
type StringInput = typeof String.Input;
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`Input`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#input)

---

<a id="is"></a>

### is

```ts
readonly is: Refinement<unknown, InferType<T>>;
```

Defined in: [packages/common/src/Type.ts:408](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L408)

A **type guard** that checks whether an unknown value satisfies the
[Type](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).

### Example

```ts
const value: unknown = "hello";
if (String.is(value)) {
  // TypeScript now knows `value` is 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"]
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`is`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#is)

---

<a id="name"></a>

### name

```ts
readonly name: "Optional";
```

Defined in: [packages/common/src/Type.ts:276](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L276)

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`name`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#name-1)

---

<a id="ornull"></a>

### orNull

```ts
readonly orNull: (value: InferInput) =>
  | InferType<T>
  | null;
```

Defined in: [packages/common/src/Type.ts:372](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L372)

Creates `T` from an `Input` value, returning `null` if validation fails.

This is a convenience method that combines `from` with `getOrNull`.

**When to use:**

- When you need to convert a validation result to a nullable value
- When the error is not important and you just want the value or nothing

### Example

```ts
// Good: Optional user input
const age = PositiveInt.orNull(userInput);
if (age != null) {
  console.log("Valid age:", age);
}

// Good: Default fallback
const maxRetries = PositiveInt.orNull(config.retries) ?? 3;

// Avoid: When you need to know why validation failed (use `from` instead)
const result = PositiveInt.from(userInput);
if (!result.ok) {
  console.error(formatPositiveError(result.error));
}
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`orNull`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#ornull)

---

<a id="orthrow"></a>

### orThrow

```ts
readonly orThrow: (value: InferInput) => InferType;
```

Defined in: [packages/common/src/Type.ts:341](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L341)

Creates `T` from an `Input` value, throwing an error if validation fails.

Use this where failure should crash the current flow instead of being
handled locally.

Throws an Error with the Type validation error in its `cause` property,
making it debuggable while avoiding the need for custom error messages.

This is a convenience method that combines `from` with `getOrThrow`.

**When to use:**

- Application startup or composition-root setup where errors must stop the
  program immediately. In Evolu apps, errors are handled by
  platform-specific `createRun` adapters at the app boundary.
- Module-level constants
- Test setup with values that are expected to be valid
- As an alternative to assertions when the Type error in the thrown Error's
  `cause` provides sufficient debugging information

Prefer `from` in ordinary application logic where the caller can recover,
show validation errors, or choose a different flow.

For clearer test failure messages on invalid input, use Vitest
`schemaMatching` + `assert` with `.is()`.

### Example

```ts
// Good: Known valid constant
const maxRetries = PositiveInt.orThrow(3);

// Good: App configuration that should crash on invalid values
const appName = Name.orThrow("MyApp");

// Good: Instead of assert when Type error is clear enough
// Context makes it obvious: count increments from non-negative value
const currentCount = counts.get(id) ?? 0;
const newCount = PositiveInt.orThrow(currentCount + 1);

// Good: Test setup with known valid values
const testUser = User.orThrow({ name: "Alice", age: 30 });

// Avoid: User input (use `from` instead)
const userAge = PositiveInt.orThrow(userInput); // Could crash!

// Better: Handle user input gracefully
const ageResult = PositiveInt.from(userInput);
if (!ageResult.ok) {
  // Handle validation error
}
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`orThrow`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#orthrow)

---

<a id="parent"></a>

### parent

```ts
readonly parent: T;
```

Defined in: [packages/common/src/Type.ts:4370](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L4370)

---

<a id="parent-1"></a>

### Parent

```ts
Parent: InferParent<T>;
```

Defined in: [packages/common/src/Type.ts:272](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L272)

The parent type.

### Example

```ts
type StringParent = typeof String.Parent;
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`Parent`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#parent)

---

<a id="parenterror"></a>

### ParentError

```ts
ParentError: InferParentError<T>;
```

Defined in: [packages/common/src/Type.ts:274](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L274)

The parent's error.

### Example

```ts
type StringParentError = typeof String.ParentError;
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`ParentError`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#parenterror)

---

<a id="type"></a>

### Type

```ts
readonly Type: InferType;
```

Defined in: [packages/common/src/Type.ts:421](https://github.com/evoluhq/evolu/blob/e7144e2bbe9069362b62dec1b64a8aa922b8f1b0/packages/common/src/Type.ts#L421)

The type this Type resolves to.

### Example

```ts
type String = typeof String.Type;
```

#### Inherited from

[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type).[`Type`](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type#type)