API reference › @evolu/common › Type › 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:12525
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. Wrapping an optional property with withDefault keeps the
input optional and makes the decoded output required. A default for a
nullable or undefined-accepting Type alone does not make the property
optional.
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 userFromInput.value, typeof User.Output>();
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:12563
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<(typeof result.value)["x-request-id"], string | undefined>();
Call Signature
function object<Props>(
props: Props,
...validation: [ObjectValidationError<Props>] extends [never]
? []
: [ValidationFailure<ObjectValidationError<Props>>]
): ObjectType<Props>;
Defined in: packages/common/src/Type.ts:12584
Creates an Object Type with explicit defaults for optional inputs.
Call Signature
function object<Props, Rest>(
props: Props,
record: Rest,
...validation: [
ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>,
] extends [never]
? []
: [
ValidationFailure<
| ObjectValidationError<Props>
| ObjectRecordValidationError<Props, Rest>
>,
]
): ObjectType<Props, Rest>;
Defined in: packages/common/src/Type.ts:12594
Creates an Object Type with explicit defaults and additional record properties.