02Guides
Dates
types.dates: 'Date' — Date values in models, parameters and bodies.
JSON has no date type: a format: date-time value arrives as a string. By default swaggerz keeps it that way, so the types match the wire exactly and nothing runs at runtime. With types.dates: 'Date', date and date-time values are Date objects in your code, in both directions.
export default defineConfig({ spec: { version: '3.1', input: './openapi.yaml' }, types: { dates: 'Date' },});What changes
Section titled “What changes”import { getAccount } from './generated/api';
const account = await getAccount({ accountId: 'a-1' });// `createdAt` is `format: date-time`, `birthday` is `format: date`.console.log(account.createdAt.toISOString(), account.birthday?.getUTCFullYear());- Types. Models, parameters, request bodies and webhook payloads use
Datewherever the schema saysdateordate-time. - Responses are converted after they are parsed (and validated, when validation is on): valid date strings become
Dateobjects. Strings that are not valid dates stay strings, so a sloppy server does not lose data. - Requests: bodies and date parameters are encoded before they are validated and serialized.
date-timevalues become ISO strings;datevalues becomeYYYY-MM-DDin UTC. Your objects are copied, not modified. - Validation checks the wire format (
z.iso.datetime({ offset: true })andz.iso.date()with Zod,v.isoTimestamp()andv.isoDate()with Valibot, ISO dates with ArkType), so errors point at the string that was received.
For every model that contains dates, a small module (dates/<model>.ts) describes where they are, and a runtime helper of about 1.2 KB walks it. Unions, recursion, arrays, maps and discriminated subtypes are followed.
When to keep strings
Section titled “When to keep strings”Keep the default when you pass dates straight through (render them, send them back), when you use a date library that parses strings itself, or when you want the smallest client. Converting is worth it when your code computes with dates and you would otherwise parse them at every use.
Limitations
Section titled “Limitations”- A
datevalue means a calendar day without a time zone. It is encoded in UTC (2026-10-23), so build suchDates withDate.UTC(…)ornew Date('2026-10-23'), not from a local midnight. - Only
format: dateandformat: date-timeare converted;time,durationand custom formats stay strings. - Values inside schemas the client cannot see (
additionalProperties: truewithout a schema,{}) are not converted.
What's generated
openapi: 3.1.0info: title: Accounts version: '1.0'paths: /accounts/{accountId}: get: tags: [accounts] operationId: getAccount parameters: - name: accountId in: path required: true schema: type: string responses: '200': description: The account. content: application/json: schema: $ref: '#/components/schemas/Account'components: schemas: Account: type: object required: [id, createdAt] properties: id: type: string createdAt: type: string format: date-time birthday: type: string format: datemodels/account.ts
/* eslint-disable */// @generated by swaggerz. Do not edit: this file is overwritten on the next generation.
export type Account = { id: string; /** @format date-time */ createdAt: Date; /** @format date */ birthday?: Date;};dates/account.ts
/* eslint-disable */// @generated by swaggerz. Do not edit: this file is overwritten on the next generation.
import type { DateShape } from '../runtime/dates.js';
/** Where `Date` values sit in `Account`; converts responses and requests. */export const AccountDates: DateShape = { object: { createdAt: 'date-time', birthday: 'date' } };accounts/get-account.ts
/* eslint-disable */// @generated by swaggerz. Do not edit: this file is overwritten on the next generation.
import { type RequestOptions, client } from '../client.js';import { AccountDates } from '../dates/account.js';import type { Account } from '../models/account.js';import { reviveDates } from '../runtime/dates.js';import { type ApiError, type RequestError, isApiError } from '../runtime/errors.js';import type { HttpStatus } from '../runtime/types.js';
/** Parameters of {@link getAccount}. */export type GetAccountParams = { accountId: string;};
/** Response data of {@link getAccount}. */export type GetAccountResponse = Account;
/** Body of an error response of {@link getAccount}. */export type GetAccountErrorBody = unknown;
/** * The `ApiError`s {@link getAccount} rejects with: one per documented status, so checking `status` narrows `body`. * * The last member covers statuses the specification does not document. */export type GetAccountApiError = ApiError<unknown, HttpStatus<1 | 3 | 4 | 5>>;
/** Everything {@link getAccount} rejects with: an `ApiError` for an error status, or a `RequestError` when no usable response arrived. */export type GetAccountError = GetAccountApiError | RequestError;
/** * Calls `GET /accounts/{accountId}`. * * @remarks `GET /accounts/{accountId}` (operationId `getAccount`) * @param params - Request parameters. * @param options - Per-request options: `signal`, `timeout`, `headers`, `client`. * @returns `200` The account * @throws {@link ApiError} When the server responds with a non-2xx status; narrow it with {@link isGetAccountApiError}. * @throws {@link RequestError} When no usable response is received (network failure, timeout or invalid body). */export function getAccount(params: GetAccountParams, options?: RequestOptions): Promise<GetAccountResponse> { return (options?.client ?? client).request<GetAccountResponse>( { operationId: 'getAccount', method: 'GET', path: '/accounts/{accountId}', pathParams: { accountId: params.accountId }, accept: 'application/json', transformResponse: (data) => reviveDates(data, () => AccountDates), }, options, );}
/** Whether `error` is an `ApiError` rejected by {@link getAccount}. It narrows to {@link GetAccountApiError}, so checking `status` afterwards narrows `body` too. */export function isGetAccountApiError(error: unknown): error is GetAccountApiError { return ( isApiError(error) && error.operationId === 'getAccount' && error.method === 'GET' );}{ types: { dates: 'Date' } }, at build time.