A CLI tool to generate TypeScript type definitions from OpenAPI/Swagger specifications. This tool helps frontend projects maintain type safety when working with backend APIs by automatically generating TypeScript types from API documentation.
- ✅ Fetches OpenAPI/Swagger specifications from URLs or local files
- ✅ Supports OpenAPI 3.x and Swagger 2.0 (with automatic conversion)
- ✅ Generates decomposed TypeScript types in a clean directory structure
- ✅ Resolves
$refreferences automatically - ✅ Groups endpoints by path segments for better organization
- ✅ Generates types for schemas, request bodies, parameters, and responses
- ✅ Includes JSDoc comments from OpenAPI descriptions
- ✅ Configurable endpoint naming via path prefix skipping
- ✅ Generates API endpoint URL constants for type-safe API calls
- ✅ Configurable via config file or CLI flags
- ✅ Optional Prettier formatting for generated code
npm install --save-dev @kolot/swagger-type-parser
# or
pnpm add -D @kolot/swagger-type-parser
# or
yarn add -D @kolot/swagger-type-parsernpx @kolot/swagger-type-parser --input http://localhost:8000/api/v1/openapi.json --output ./src/api/typesCreate a swagger-type-parser.config.json file in your project root:
{
"input": "http://localhost:8000/api/v1/openapi.json",
"output": "./src/api/types",
"clean": true,
"pretty": true,
"verbose": false
}Then run:
npx @kolot/swagger-type-parsernpx @kolot/swagger-type-parser --config configs/swagger.config.json| Option | Short | Description | Default |
|---|---|---|---|
--input |
-i |
URL or path to OpenAPI/Swagger JSON | Required |
--output |
-o |
Output directory for generated TypeScript files | Required |
--config |
-c |
Path to config file | swagger-type-parser.config.json |
--clean |
Clean output directory before generation | false |
|
--pretty |
Format generated code with Prettier | false |
|
--verbose |
Log verbose debug information | false |
|
--path-prefix-skip |
Number of path segment pairs to skip when generating endpoint names (e.g., 1 = skip first 2 segments: "/api/v1/auth/login" → "auth_login") | 0 |
|
--generate-api-endpoints |
Generate API endpoint URL constants for easy access from frontend | false |
Note: CLI flags override values from the config file.
The tool supports multiple input sources:
-
HTTP/HTTPS URLs - Fetch from a running API server:
--input http://localhost:8000/api/v1/openapi.json --input https://api.example.com/docs/openapi.json
-
Local JSON files - Use a local OpenAPI specification:
--input ./openapi.json --input ./api-docs/swagger.json
The tool generates TypeScript types in a decomposed structure. Endpoints are organized by path segments (excluding the last segment), making it easy to navigate and maintain:
src/api/types/
├── index.ts # Main barrel exports
├── schemas/ # Schema type definitions
│ ├── User.ts
│ ├── Order.ts
│ └── Product.ts
├── endpoints/ # Endpoint type definitions (grouped by path segments)
│ ├── auth/ # Endpoints under /api/v1/auth/*
│ │ ├── auth_login.ts
│ │ ├── auth_register.ts
│ │ └── auth_me.ts
│ ├── users/ # Endpoints under /api/v1/users/*
│ │ ├── users_list.ts
│ │ └── users_create.ts
│ └── health.ts # Endpoints with single segment (e.g., /api/v1/health)
├── api/ # API endpoint URL constants (if --generate-api-endpoints is enabled)
│ └── index.ts # apiEndpoints object with nested structure
└── common/ # Common utility types
└── Http.ts # HttpMethod, RequestConfig, etc.
Note: The directory structure depends on the pathPrefixSkip configuration. With pathPrefixSkip: 1, paths like /api/v1/auth/login will be organized as endpoints/auth/auth_login.ts.
import type { User, Order, Product } from './api/types/schemas/User';
// or from barrel export
import type { User, Order, Product } from './api/types';Endpoint types are named based on the API path (not operationId). For example, /api/v1/auth/login becomes auth_login.ts (with pathPrefixSkip: 1):
import type {
auth_login_200Response,
auth_login_RequestBody
} from './api/types/endpoints/auth/auth_login';
import type {
users_list_200Response,
users_list_QueryParams
} from './api/types/endpoints/users/users_list';import type { auth_login_200Response, auth_login_RequestBody } from './api/types/endpoints/auth/auth_login';
import type { User } from './api/types/schemas/User';
async function login(email: string, password: string): Promise<auth_login_200Response> {
const body: auth_login_RequestBody = { email, password };
const response = await fetch('/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error('Login failed');
}
return response.json();
}
// Usage
const result = await login('user@example.com', 'password123');
// result is typed as auth_login_200ResponseWhen --generate-api-endpoints flag is enabled, the tool generates a nested object structure with all API endpoint URLs, organized by their folder hierarchy. This eliminates the need to manually write URL strings:
import { apiEndpoints } from './api/types/api';
import type { auth_login_200Response, auth_login_RequestBody } from './api/types/endpoints/auth/auth_login';
async function login(email: string, password: string): Promise<auth_login_200Response> {
const body: auth_login_RequestBody = { email, password };
const response = await fetch(apiEndpoints.auth.auth_login, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error('Login failed');
}
return response.json();
}
// Or with an API client
await apiClient.post<auth_login_200Response>(
apiEndpoints.auth.auth_login,
payload,
{
skipAuth: true, // Public endpoint
},
);For endpoints with path parameters (e.g., /api/v1/users/profile/{user_id}), use the buildUrl utility function to replace parameters:
import { apiEndpoints, buildUrl } from './api/types/api';
import type { users_profile_200Response, users_profile_PathParams } from './api/types/endpoints/users/users_profile';
// Single parameter
const url = buildUrl(apiEndpoints.users.users_profile, { user_id: '123' });
// Returns: '/api/v1/users/profile/123'
// Multiple parameters
const url2 = buildUrl(
apiEndpoints.dynamic_fields.dynamic_fields_entities,
{ entity_type: 'user_profile', entity_id: '456' }
);
// Returns: '/api/v1/dynamic-fields/entities/user_profile/456'
// Type-safe usage with PathParams
async function getUserProfile(userId: string): Promise<users_profile_200Response> {
const params: users_profile_PathParams = { user_id: userId };
const url = buildUrl(apiEndpoints.users.users_profile, params);
const response = await fetch(url, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
});
return response.json();
}
// Endpoints without parameters work as-is
const loginUrl = apiEndpoints.auth.auth_login;
// No need to use buildUrl for endpoints without parametersThe apiEndpoints object structure matches the endpoint folder organization:
// Generated structure example (with pathPrefixSkip: 1)
export const apiEndpoints = {
auth: {
auth_login: '/api/v1/auth/login',
auth_register: '/api/v1/auth/register',
auth_me: '/api/v1/auth/me',
},
users: {
users_list: '/api/v1/users',
users_detail: '/api/v1/users/{id}',
},
// ...
} as const;Benefits:
- ✅ Type-safe endpoint URLs (autocomplete support)
- ✅ No manual URL string writing
- ✅ Automatic updates when API changes
- ✅ Consistent with endpoint type organization
- Schemas: Use the schema name from
components.schemas(e.g.,User,Order) - Endpoints: Based on API path converted to snake_case (e.g.,
/api/v1/auth/login→auth_login) - Request Bodies:
{endpointName}_RequestBody(e.g.,auth_login_RequestBody) - Responses:
{endpointName}_{statusCode}Response(e.g.,auth_login_200Response) - Parameters:
{endpointName}_PathParams,{endpointName}_QueryParams,{endpointName}_HeaderParams
All generated types include JSDoc comments from OpenAPI descriptions when available.
The tool maps OpenAPI/JSON Schema types to TypeScript as follows:
| OpenAPI Type | TypeScript Type |
|---|---|
string |
string |
integer, number |
number |
boolean |
boolean |
array |
T[] |
object |
{ ... } |
enum |
'value1' | 'value2' |
oneOf |
Type1 | Type2 |
anyOf |
Type1 | Type2 |
allOf |
Type1 & Type2 |
nullable: true |
T | null |
The config file (swagger-type-parser.config.json) supports the following options:
{
"input": "http://localhost:8000/api/v1/openapi.json",
"output": "./src/api/types",
"clean": true,
"pretty": true,
"verbose": false,
"pathPrefixSkip": 1
}input(required): URL or path to OpenAPI/Swagger JSONoutput(required): Output directory for generated filesclean(optional): Remove all files in output directory before generationpretty(optional): Format generated code with Prettier (requires Prettier to be installed)verbose(optional): Enable verbose loggingpathPrefixSkip(optional): Number of path segment pairs to skip when generating endpoint namesgenerateApiEndpoints(optional): Generate API endpoint URL constants for easy access from frontend0(default): Use full path -/api/v1/auth/login→api_v1_auth_login1: Skip first 2 segments -/api/v1/auth/login→auth_login2: Skip first 4 segments -/api/v1/auth/login→ (empty, would beroot)
The pathPrefixSkip option helps customize endpoint naming based on your API structure:
# Skip /api/v1 prefix
npx @kolot/swagger-type-parser --input openapi.json --output ./types --path-prefix-skip 1
# Result: /api/v1/auth/login → endpoints/auth/auth_login.ts
# Result: /api/v1/users → endpoints/users.tsThis is especially useful when you want shorter, more meaningful endpoint names without the API version prefix.
All generated types include JSDoc comments extracted from OpenAPI descriptions:
/**
* User account information
*
* Contains basic user profile data and authentication status.
*/
export type User = {
/** Unique user identifier */
id: number;
/** User's email address */
email: string;
/** User's full name */
name?: string;
};Endpoints are automatically organized into folders based on their path segments. This makes it easy to:
- Find related endpoints
- Maintain a clean project structure
- Navigate large API specifications
For example, with pathPrefixSkip: 1:
/api/v1/auth/login→endpoints/auth/auth_login.ts/api/v1/auth/register→endpoints/auth/auth_register.ts/api/v1/users/list→endpoints/users/users_list.ts
Path parameters (e.g., {id}, {entity_type}) are automatically removed from endpoint names and folder structure:
/api/v1/users/{id}→endpoints/users/users.ts(notusers_{id}.ts)/api/v1/entities/{type}/{id}→endpoints/entities/entities.ts
- External
$refreferences (outside the specification) are not supported - Complex OpenAPI features like
discriminatormay not be fully supported - Prettier formatting requires Prettier to be installed in your project
- Some edge cases in Swagger 2.0 to OpenAPI 3.x conversion may not be handled
- Endpoint names are based on paths, not
operationId(for consistency and predictability)
Potential enhancements for future versions:
- Generate a typed HTTP client helper
- Support for external
$refreferences - Better handling of
discriminatorand other advanced OpenAPI features - Support for generating React Query hooks
- Custom type name mapping
- Support for multiple OpenAPI specs in one run
npm run buildnpm testnpm run lintnpm run formatMIT
Contributions are welcome! Please feel free to submit a Pull Request.