openapi-typesafe
openapi-typesafe turns OpenAPI 3.x documents into TypeScript types with Node.js. No Java, no node-gyp, no running OpenAPI server.
It is a drop-in successor to openapi-typescript 7.13, with the same CLI flags and the same Node API. Its output is compared with openapi-typescript's on 1,820 real-world documents with 28 option sets (50,960 cases): 99.99% of the outputs are the same byte for byte and 100% have the same types (compatibility report). The migration guide lists the changes: output that did not compile or had wrong types, and open string enums, a change merged upstream after 7.13.0. The difference is inside: openapi-typesafe prints types itself instead of through the TypeScript compiler API, so it works in projects on TypeScript 7 (see TypeScript 7). Coming from openapi-typescript? See the migration guide.
Release candidate
The current version is a 1.0.0 release candidate (1.0.0-rc.N); names and output can still change before 1.0.0.
The code is MIT-licensed and free to use.
TIP
New to OpenAPI? Speakeasy’s Intro to OpenAPI explains the “why” and “how” of OpenAPI.
Features
- Supports OpenAPI 3.0, 3.1 and 3.2 (including advanced features like discriminators; see OpenAPI 3.2 features)
- Generates runtime-free types
- Loads documents from YAML or JSON, locally or remotely
- Generates types for a large document in about a second (GitHub's REST API)
- Works with TypeScript 5.4 and newer, including 6 and 7; the generator itself needs no TypeScript package
OpenAPI 2.x (Swagger) is not supported.
OpenAPI 3.2 features
A 3.2 document generates the same types as a 3.1 document with the same content, plus types for the 3.2 additions. A document that uses none of them gets the same output as before.
Experimental
The types generated for the 3.2 additions in the table below are experimental in 1.x: a minor release may change their shape, for example to match openapi-typescript once it supports 3.2. Such a change is named in the changelog. The output of documents that use none of these keys, client.QUERY() and the "query" member of HttpMethod are not experimental (Versioning).
| 3.2 feature | Generated types |
|---|---|
query operation | a query member after trace, only in path items that have one; client.QUERY() calls it |
additionalOperations | an additionalOperations member keyed by the exact method name (SUBSCRIBE); the operations are typed, the clients do not call them |
itemSchema | an itemContent map next to content, with the type of one item per media type; content keeps the schema type (or unknown) |
in: querystring | the schema of its content becomes parameters.query |
components.mediaTypes | a mediaTypes member of components, and content entries that reference it |
"/trips": {
// …
trace?: never;
additionalOperations: {
SUBSCRIBE: operations["subscribe-trip"];
};
};
// operations["subscribe-trip"]["responses"][200]
{
headers: { [name: string]: unknown };
content: { "application/jsonl": unknown };
itemContent: { "application/jsonl": components["schemas"]["TripUpdate"] };
}itemContent is not the response data: a stream such as application/jsonl is read with parseAs: "stream" and split into items by your code, which can use the item type.
A querystring parameter is sent with the client's querySerializer, which writes form fields (application/x-www-form-urlencoded). For another media type, such as JSON in the query string, pass your own querySerializer. 3.2 does not allow in: query parameters next to a querystring parameter; if a document has both, the query parameters are typed, and the generator warns about the querystring parameter with its JSON Pointer.
Other 3.2 additions do not change types: $self, itemEncoding, prefixEncoding, tag parent and kind, and discriminator.defaultMapping (the default schema still gets its own name as the discriminator value). A discriminator without propertyName adds no property type.
Examples
Setup
openapi-typesafe needs Node.js 22.12 or newer. In your project, run:
npm i -D openapi-typesafeAnd in your tsconfig.json, to load the types properly:
{
"compilerOptions": {
"module": "ESNext", // or "NodeNext"
"moduleResolution": "Bundler" // or "NodeNext"
}
}Highly recommended
Also adding the following can boost type safety:
{
"compilerOptions": {
"noUncheckedIndexedAccess": true
}
}Basic usage
First, generate a local type file by running npx openapi-typesafe, first specifying your input document (JSON or YAML), and where you’d like the --output (-o) to be saved:
# Local document
npx openapi-typesafe ./path/to/my/schema.yaml -o ./path/to/my/schema.d.ts
# Remote document
npx openapi-typesafe https://myapi.dev/api/v1/openapi.yaml -o ./path/to/my/schema.d.tsThen in your TypeScript project, import types where needed:
import type { paths, components } from "./my-openapi-3-schema"; // generated by openapi-typesafe
// Schema Obj
type MyType = components["schemas"]["MyType"];
// Path params
type EndpointParams = paths["/my/endpoint"]["parameters"];
// Response obj
type SuccessResponse =
paths["/my/endpoint"]["get"]["responses"][200]["content"]["application/json"];
type ErrorResponse =
paths["/my/endpoint"]["get"]["responses"][500]["content"]["application/json"];With "moduleResolution": "NodeNext", write the extension: "./my-openapi-3-schema.js".
From here, you can use these types for any of the following (but not limited to):
- Using an OpenAPI-supported fetch client (like openapi-typesafe-fetch)
- Asserting types for other API request bodies and responses
- Building core business logic based on API types
- Validating mock test data is up-to-date with the current schema
- Packaging API types into any npm packages you publish (such as client SDKs, etc.)