API reference@evolu/commonType › object

Call Signature

function object<Props>(
  props: Props,
  ...validation: [ObjectValidationError<Props>] extends [never]
    ? []
    : [ValidationFailure<ObjectValidationError<Props>>]
): StrictObjectType<Props>;

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

Plain object Type.

Use object(props) for objects with fixed property names. Properties are required unless wrapped with optional. An optional property may be absent, but a present value is still validated and does not implicitly accept undefined.

Without a second argument, fromUnknown rejects additional properties. Pass a record with the predefined String key Type to validate and preserve additional string-keyed properties.

fromUnknown requires a plain object. Plain object Types model only own enumerable data properties, so Object prototype properties neither satisfy required properties nor make optional properties present. This keeps Outputs valid after ordinary object spread restores Object.prototype.

The prototype must satisfy the realm-neutral structural heuristic described by isPlainObject. A matching custom root prototype can be classified as plain; other custom prototypes, class instances, accessors, and non-enumerable properties are rejected. Use instanceOf for class Outputs or transform to decode instances into plain data.

When decoding changes no property, it preserves the input. When decoding or encoding changes a property, it constructs an object with a null prototype.

By default, validation returns the first property issue. Pass { errors: "all" } to collect all issues.

Example

import {
  assertOk,
  assertType,
  Int64FromInt64String,
  String,
  object,
  type InferType,
} from "@evolu/common";

const User = object({
  name: String,
  loginCount: Int64FromInt64String,
});
interface User extends InferType<typeof User> {}

// Validate an unknown value.
const userFromUnknown = User.fromUnknown({
  name: "Ada",
  loginCount: "42",
});

assertOk(userFromUnknown, { name: "Ada", loginCount: 42n });

// Validate the object and root property Types.
const userInput = User.parent.fromUnknown({
  name: "Ada",
  loginCount: "42",
});
assertOk(userInput, { name: "Ada", loginCount: "42" });

// Run the remaining property stages.
const userFromInput = User.from.parent(userInput.value);

assertOk(userFromInput, { name: "Ada", loginCount: 42n });
assertType<typeof User.Output, typeof userFromInput.value>();

Note that TypeScript does not model an object's runtime prototype. This can make a plain TypeScript object interpret an inherited Object.prototype name as an object property:

import { assertEqual, assertErr, assertTrue, trySync } from "@evolu/common";

interface Values {
  readonly toString?: number;
}

const nullPrototypeValues = Object.create(null) as Values;
const values = { ...nullPrototypeValues };

// TypeScript treats the inherited function as `number | undefined`.
const value: number | undefined = values.toString;
const valueType = typeof value;

assertEqual(valueType, "function");
const called = trySync(
  () => {
    if (value !== undefined) value.toFixed(0);
  },
  (error) => error,
);
assertErr(called);
assertTrue(called.error instanceof TypeError);

Evolu Object Outputs use the same TypeScript object representation.

import {
  assertEqual,
  assertErr,
  assertOk,
  assertTrue,
  trySync,
  Number,
  object,
  optional,
  type Data,
} from "@evolu/common";

const Values = object({ toString: optional(Number) });
const result = Values.fromUnknown({});
const emptyValues: Data = {};

assertOk(result, emptyValues);

const value: number | undefined = result.value.toString;
const valueType = typeof value;

assertEqual(valueType, "function");
const called = trySync(
  () => {
    if (value !== undefined) value.toFixed(0);
  },
  (error) => error,
);
assertErr(called);
assertTrue(called.error instanceof TypeError);

In other words, treat Object Outputs as data rather than calling inherited object methods through them.

Call Signature

function object<Props, Rest>(
  props: Props,
  record: Rest,
  ...validation: [
    ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>,
  ] extends [never]
    ? []
    : [
        ValidationFailure<
          | ObjectValidationError<Props>
          | ObjectRecordValidationError<Props, Rest>
        >,
      ]
): ObjectWithRecordType<
  Props,
  Rest extends ObjectRecordTypeNode ? Rest : never
>;

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

Creates an Object Type with additional record properties.

Example

import { assertOk, assertType, String, object, record } from "@evolu/common";

const RequestHeaders = object(
  { authorization: String },
  record(String, String),
);
const result = RequestHeaders.fromUnknown({
  authorization: "Bearer token",
  "x-request-id": "request-1",
});

assertOk(result, {
  authorization: "Bearer token",
  "x-request-id": "request-1",
});
assertType<string | undefined, (typeof result.value)["x-request-id"]>();