Skip to content

Conversation

@klh
Copy link

@klh klh commented Nov 19, 2025

Summary

Adds a .withExample() method to Zod v4 schemas that attaches type-safe example values via the metadata system. Examples are stored in an examples?: unknown[] array in GlobalMeta, enabling multiple examples per schema through method chaining.

Motivation

Complex schemas that are merged, inherited, and unioned/combined can be hard to understand at a glance. withExample provides:

  • Inline documentation - See exactly what valid data looks like right where the schema is defined
  • Type-safe examples - TypeScript validates that examples match the schema's inferred type, warning immediately if they're incorrect
  • Schema introspection - Tools can extract examples for documentation generation, API specs, or testing
  • Self-documenting code - New developers can understand complex schemas by seeing concrete examples

This is particularly valuable for:

  • Documentation generation
  • API specifications (OpenAPI/JSON Schema)
  • AI-powered tools that benefit from concrete examples
  • Large codebases with complex, nested schemas

Implementation

  • Added examples?: unknown[] field to GlobalMeta interface in packages/zod/src/v4/core/registries.ts
  • Added .withExample() method to ZodType interface and implementation
  • Example values are fully type-checked against the schema's inferred type
  • Examples are stored in a metadata array, allowing multiple examples per schema
  • Method is chainable - each call appends to the examples array
  • Added comprehensive test coverage in with-example.test.ts (10 tests)
  • Updated documentation in packages/docs/content/metadata.mdx

Example Usage

Simple Schema

const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
}).withExample({ name: 'John Doe', age: 30 });

UserSchema.meta()?.examples;
// => [{ name: 'John Doe', age: 30 }]

Complex Merged/Inherited Schema

// Without withExample - hard to know what the final shape looks like
const BaseMessage = z.object({
  action: z.literal('command'),
});

const Settings = z.object({
  name: z.string(),
  xref: z.boolean(),
  custom_parts: z.boolean(),
});

const ComplexSchema = BaseMessage.merge(Settings).extend({
  type: z.literal('assembly'),
  command: z.enum(['build', 'test']),
  db_env: z.enum(['PROD', 'DEV']),
});

// With .withExample() - immediately clear what valid data looks like
// AND TypeScript will error if the example doesn't match the schema!
const ComplexSchemaWithExample = ComplexSchema.withExample({
  action: 'command',
  name: 'ASY_ART_90628285_S01_NV01',
  xref: true,
  custom_parts: false,
  type: 'assembly',
  command: 'build',
  db_env: 'PROD',
});

Type Safety in Action

// TypeScript catches errors immediately in your IDE:
const BadExample = z.object({ age: z.number() })
  .withExample({ age: "30" });  // ❌ TypeScript error: Type 'string' is not assignable to type 'number'

// This makes it a GREAT inline code documentation AND verification tool!

Union Types & Multiple Examples

// Unions can be confusing - examples make them crystal clear
// You can chain multiple examples to show different valid shapes
const ResponseSchema = z.union([
  z.object({ status: z.literal('success'), data: z.string() }),
  z.object({ status: z.literal('error'), message: z.string() }),
])
  .withExample({ status: 'success', data: 'Operation completed' })
  .withExample({ status: 'error', message: 'Something went wrong' });

ResponseSchema.meta()?.examples;
// => [
//   { status: 'success', data: 'Operation completed' },
//   { status: 'error', message: 'Something went wrong' }
// ]

Benefits

  1. Type-verified documentation - Examples are checked by TypeScript, ensuring they never drift from the schema
  2. IDE integration - Get instant feedback if an example is invalid
  3. Self-documenting APIs - Other developers see valid data structures immediately
  4. Tooling support - Examples can be extracted for OpenAPI specs, test generation, or AI training

Testing

All tests pass - Full test suite passes including 10 new tests for .withExample()

Test Coverage:

  • Primitive types (string, number, boolean, null)
  • Complex objects and nested schemas
  • Array schemas
  • Union types
  • Multiple chained examples
  • Validation preservation (examples don't affect schema validation)
  • Metadata retrieval via schema.meta()?.examples
  • Integration with other Zod methods (.optional(), etc.)

Test Results: 3,156 tests passing (3,146 existing + 10 new)

Add z.withExample() helper that attaches example values to schemas by encoding them as JSON in the schema's description field. This is useful for documentation generation, API specifications, and AI-powered tools.

- Implement withExample function in schemas.ts
- Add comprehensive test coverage in with-example.test.ts
- Document withExample in metadata.mdx
- Example values are type-checked against schema's inferred type
@vercel
Copy link

vercel bot commented Nov 19, 2025

@klh is attempting to deploy a commit to the colinhacks Team on Vercel.

A member of the Team first needs to authorize it.

Add .withExample() method that attaches example values to schemas via metadata.
Examples are stored in an examples array in GlobalMeta, supporting multiple examples.

- Added examples?: unknown[] to GlobalMeta interface
- Added .withExample() method to ZodType with full type safety
- Chainable method syntax: schema.withExample(value)
- Uses Array.isArray() and Object.assign() for type safety
- 10 comprehensive tests covering all use cases
- Updated documentation with examples
small bump commit to trigger actions again
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant