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);
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);
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);
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);
Comparison
const blank = jt.value.create(BookSchema.$id);
// Zero-values + explicit defaults; all required fields present// 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.// 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.// Limitation: io-ts has no zero-value creator.
// BookCodec.decode({}) fails on required fields. Build the blank object
// manually for form scaffolding.import { Value } from '@sinclair/typebox/value';
// Value.Create fills all fields with type defaults + declared defaults:
const blank = Value.Create(BookSchema);// 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.# 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)// Limitation: feature not directly supported in Yup. See /comparisons for the matrix.// Limitation: feature not directly supported in Joi. See /comparisons for the matrix.// Limitation: feature not directly supported in Effect Schema. See /comparisons for the matrix.// Limitation: feature not directly supported in ArkType. See /comparisons for the matrix.// Limitation: feature not directly supported in Runtypes. See /comparisons for the matrix.Related
JsonTology.materialize- fill from partial trusted data + declared defaultsCompose.getDefaults- extract only declared defaults (no zero-values)JsonTology.instantiate- validate + fill defaults + strip unknowns (for real data)
See also
- Bookstore domain - where
BookSchemaandCustomerSchemaare defined