Skip to content

value.create

Declaration. Synthesizes a zero-value default instance for a schema by filling every declared property with its default value if present, or with a type-based zero value if no default is declared ('' for string, 0 for number/integer, false for boolean, [] for array, {} for object). Called with a registered $id, it returns the schema's inferred type (ParseOutputType<TRefs[K], TRefs>) directly — no cast needed; an unregistered string $id returns unknown.

Use this when you need a blank structural skeleton for a schema - for example, pre-populating a form's initial state where every field should have a zero value. Contrast with materialize(schema) which only fills declared defaults (leaves undeclared fields absent) and throws if required fields without defaults are missing.

Don't use this when you want a validated, coerced value from real input (use instantiate). Don't use it when you only want declared defaults without zero-values (use Compose.getDefaults).

Examples

Example 1: Blank Book form state

/**
 * value.create — Example 1: Zero-value instance for form initialization
 * Demonstrates: zero-values for required fields, explicit defaults preserved
 *
 * BookSchema is an allOf-composed schema (Compose.subClassOf). value.create
 * traverses all allOf members — including $ref parents — synthesizes zero-values
 * for every required field, and applies declared defaults. The result covers
 * both inherited bibliographic fields (isbn, title, authors) and own retail
 * fields (inStock with default true, price, printStatus zero-values).
 */

import type { InferType } from '../../../src/types/index.js';
import {
  BibliographicRecordSchema, BookSchema, bookstoreEntities
} from '../bookstore/index.js';
import type { BookstoreRefs } from '../bookstore/index.js';

type BibliographicRecord = InferType<typeof BibliographicRecordSchema, BookstoreRefs>;

// value.create on a flat schema — behavior unchanged.
const blank: BibliographicRecord = bookstoreEntities.value.create(BibliographicRecordSchema.$id);

// Required fields with no default get zero-values
console.assert(blank.isbn === '');
console.assert(blank.title === '');
console.assert(Array.isArray(blank.authors));

console.log('blank isbn:', blank.isbn);
console.log('blank title:', blank.title);
console.log('blank authors:', blank.authors);

// value.create on an allOf-composed schema — synthesizes inherited + own fields.
const bookBlank = bookstoreEntities.value.create(BookSchema.$id) as Record<string, unknown>;

// Inherited from BibliographicRecordSchema via the $ref allOf member
console.assert(bookBlank.isbn === '');
console.assert(bookBlank.title === '');
console.assert(Array.isArray(bookBlank.authors));

// Own field with declared default: true
console.assert(bookBlank.inStock === true);

console.log('bookBlank isbn (inherited zero-value):', bookBlank.isbn);
console.log('bookBlank inStock (own default):', bookBlank.inStock);
Output
Press Execute to run this example against the real library.

Example 2: Blank Customer for testing

/**
 * value.create — Example 2: Blank Customer for testing
 * Demonstrates: zero-values for all required fields, addresses default []
 *
 * Creates a blank Customer instance — every string field gets '' and the
 * addresses array gets its declared default []. Useful for pre-populating
 * form initial state without requiring test fixture data.
 */

import {
  bookstoreEntities, CustomerSchema
} from '../bookstore/index.js';

const blankCustomer = bookstoreEntities.value.create(CustomerSchema.$id) as Record<string, unknown>;

// Required string fields get zero-values.
console.assert((blankCustomer as { 'customerId': string }).customerId === '');
console.assert((blankCustomer as { 'email': string }).email === '');
console.assert((blankCustomer as { 'name': string }).name === '');

// addresses has a declared default of [] — applied here.
console.assert(Array.isArray((blankCustomer as { 'addresses': unknown[] }).addresses));
console.assert((blankCustomer as { 'addresses': unknown[] }).addresses.length === 0);

console.log('blank customerId:', (blankCustomer as { 'customerId': string }).customerId);
console.log('blank email:', (blankCustomer as { 'email': string }).email);
console.log('blank addresses:', (blankCustomer as { 'addresses': unknown[] }).addresses);
Output
Press Execute to run this example against the real library.

Example 3: Contrast with materialize and Compose.getDefaults

/**
 * value.create — Example 3: Contrast with materialize and Compose.getDefaults
 * Demonstrates: three construction paths with distinct semantics
 *
 * Shows the difference between value.create (zero-values + defaults),
 * Compose.getDefaults (declared defaults only), and materialize (partial
 * trusted data + defaults). The canonical Neverending Story rare-book
 * fixture provides the required fields for materialize.
 *
 * value.create on an allOf-composed schema (Compose.subClassOf):
 *   Traverses all allOf members, resolves $ref parents recursively,
 *   synthesizes zero-values for required fields, and applies declared
 *   defaults. The result carries inherited + own fields merged.
 *
 * Compose.getDefaults on an allOf-composed schema:
 *   Traverses inline allOf members that carry properties. $ref-only members
 *   are skipped (no registry available for resolution). Returns declared
 *   defaults from all reachable inline members merged.
 */

import {
  Compose
} from '../../../src/index.js';
import {
  aboxFixtures, BibliographicRecordSchema, BookSchema, bookstoreEntities
} from '../bookstore/index.js';
import type { Book } from '../bookstore/index.js';

// value.create on BookSchema — allOf-composed (Compose.subClassOf).
// Inherits isbn/title/authors from BibliographicRecordSchema via $ref,
// adds own retail fields, and applies inStock: true declared default.
const fromCreate = bookstoreEntities.value.create(BookSchema.$id) as Record<string, unknown>;

// Inherited required fields synthesized with zero-values
console.assert(fromCreate.isbn === '');
console.assert(fromCreate.title === '');
console.assert(Array.isArray(fromCreate.authors));

// Own field with declared default applied
console.assert(fromCreate.inStock === true);

// BibliographicRecordSchema is flat — behavior unchanged.
const fromBiblio = bookstoreEntities.value.create(BibliographicRecordSchema.$id) as Record<string, unknown>;

console.assert(fromBiblio.isbn === '');
console.assert(fromBiblio.title === '');

// Compose.getDefaults — only declared defaults (no zero-values).
// BookSchema allOf member body carries inStock: {default: true};
// the $ref-pointing allOf member (BibliographicRecord) has no defaults.
const defaults = Compose.getDefaults(BookSchema);

console.assert(defaults.inStock === true);

// BibliographicRecord has no declared defaults on any property.
const bibDefaults = Compose.getDefaults(BibliographicRecordSchema);

console.assert(!('isbn' in bibDefaults));
console.assert(!('title' in bibDefaults));
console.assert(!('authors' in bibDefaults));

// materialize — fill declared defaults, partial is trusted, throws if required missing.
// Works correctly with composed schemas; resolves inherited + own required fields.
// materialize resolves inherited + own required fields at runtime; the static
// MaterializedSchemaType surfaces own properties only, so view the result as the
// fully-resolved Book to read the inherited `isbn` precisely.
const materialized = bookstoreEntities.materialize(BookSchema, {
  'authors': [...aboxFixtures.rareBook.authors],
  'isbn': aboxFixtures.rareBook.isbn,
  'price': aboxFixtures.rareBook.price,
  'printStatus': aboxFixtures.rareBook.printStatus,
  'title': aboxFixtures.rareBook.title
}) as Book;

console.assert(materialized.isbn === aboxFixtures.rareBook.isbn);
console.assert(materialized.inStock === true);

console.log('create isbn (zero-value):', fromCreate.isbn);
console.log('create inStock (default applied):', fromCreate.inStock);
console.log('getDefaults inStock (declared):', defaults.inStock);
console.log('getDefaults BibliographicRecord keys (none declared):', Object.keys(bibDefaults));
console.log('materialize isbn (from data):', materialized.isbn);
console.log('materialize inStock (default true applied):', materialized.inStock);
Output
Press Execute to run this example against the real library.

Bad examples - what NOT to do

Anti-pattern 1: Using value.create to generate valid instances for tests

/**
 * value.create — Example 3: Contrast with materialize and Compose.getDefaults
 * Demonstrates: three construction paths with distinct semantics
 *
 * Shows the difference between value.create (zero-values + defaults),
 * Compose.getDefaults (declared defaults only), and materialize (partial
 * trusted data + defaults). The canonical Neverending Story rare-book
 * fixture provides the required fields for materialize.
 *
 * value.create on an allOf-composed schema (Compose.subClassOf):
 *   Traverses all allOf members, resolves $ref parents recursively,
 *   synthesizes zero-values for required fields, and applies declared
 *   defaults. The result carries inherited + own fields merged.
 *
 * Compose.getDefaults on an allOf-composed schema:
 *   Traverses inline allOf members that carry properties. $ref-only members
 *   are skipped (no registry available for resolution). Returns declared
 *   defaults from all reachable inline members merged.
 */

import {
  Compose
} from '../../../src/index.js';
import {
  aboxFixtures, BibliographicRecordSchema, BookSchema, bookstoreEntities
} from '../bookstore/index.js';
import type { Book } from '../bookstore/index.js';

// value.create on BookSchema — allOf-composed (Compose.subClassOf).
// Inherits isbn/title/authors from BibliographicRecordSchema via $ref,
// adds own retail fields, and applies inStock: true declared default.
const fromCreate = bookstoreEntities.value.create(BookSchema.$id) as Record<string, unknown>;

// Inherited required fields synthesized with zero-values
console.assert(fromCreate.isbn === '');
console.assert(fromCreate.title === '');
console.assert(Array.isArray(fromCreate.authors));

// Own field with declared default applied
console.assert(fromCreate.inStock === true);

// BibliographicRecordSchema is flat — behavior unchanged.
const fromBiblio = bookstoreEntities.value.create(BibliographicRecordSchema.$id) as Record<string, unknown>;

console.assert(fromBiblio.isbn === '');
console.assert(fromBiblio.title === '');

// Compose.getDefaults — only declared defaults (no zero-values).
// BookSchema allOf member body carries inStock: {default: true};
// the $ref-pointing allOf member (BibliographicRecord) has no defaults.
const defaults = Compose.getDefaults(BookSchema);

console.assert(defaults.inStock === true);

// BibliographicRecord has no declared defaults on any property.
const bibDefaults = Compose.getDefaults(BibliographicRecordSchema);

console.assert(!('isbn' in bibDefaults));
console.assert(!('title' in bibDefaults));
console.assert(!('authors' in bibDefaults));

// materialize — fill declared defaults, partial is trusted, throws if required missing.
// Works correctly with composed schemas; resolves inherited + own required fields.
// materialize resolves inherited + own required fields at runtime; the static
// MaterializedSchemaType surfaces own properties only, so view the result as the
// fully-resolved Book to read the inherited `isbn` precisely.
const materialized = bookstoreEntities.materialize(BookSchema, {
  'authors': [...aboxFixtures.rareBook.authors],
  'isbn': aboxFixtures.rareBook.isbn,
  'price': aboxFixtures.rareBook.price,
  'printStatus': aboxFixtures.rareBook.printStatus,
  'title': aboxFixtures.rareBook.title
}) as Book;

console.assert(materialized.isbn === aboxFixtures.rareBook.isbn);
console.assert(materialized.inStock === true);

console.log('create isbn (zero-value):', fromCreate.isbn);
console.log('create inStock (default applied):', fromCreate.inStock);
console.log('getDefaults inStock (declared):', defaults.inStock);
console.log('getDefaults BibliographicRecord keys (none declared):', Object.keys(bibDefaults));
console.log('materialize isbn (from data):', materialized.isbn);
console.log('materialize inStock (default true applied):', materialized.inStock);
Output
Press Execute to run this example against the real library.

Comparison

ts
const blank = jt.value.create(BookSchema.$id);
// Zero-values + explicit defaults; all required fields present
ts
// Zod doesn't provide a zero-value creator.
// Closest: schema.parse({})  - fails for required fields without defaults.
// Use z.object({ ... }).optional()... with explicit defaults, or build manually.
ts
// Limitation: Valibot has no zero-value creator.
// v.parse(BookSchema, {}) fails on required fields without v.optional defaults.
// Build the blank object manually for forms.
ts
// Limitation: io-ts has no zero-value creator.
// BookCodec.decode({}) fails on required fields. Build the blank object
// manually for form scaffolding.
ts
import { Value } from '@sinclair/typebox/value';
// Value.Create fills all fields with type defaults + declared defaults:
const blank = Value.Create(BookSchema);
ts
// AJV has no built-in zero-value creator.
// Workaround: validate an empty object with { useDefaults: true }:
const ajv = new Ajv({ useDefaults: true });
const blank = {};
ajv.validate(bookSchema, blank);
// Limitation: mutates the object in place; only fills declared defaults (not zero-values);
// missing required fields stay absent; no TypeScript type narrowing.
py
# Pydantic requires values for required fields  - no zero-value creation.
# Use Optional fields with None defaults or supply explicit test values:
Book(isbn='', title='', authors=[], price=0)
ts
// Limitation: feature not directly supported in Yup. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in Joi. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in Effect Schema. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in ArkType. See /comparisons for the matrix.
ts
// Limitation: feature not directly supported in Runtypes. See /comparisons for the matrix.

See also

Released under the MIT License.