Migration: @kubb/plugin-ts
Part of the v4 → v5 migration guide. See the full option reference in @kubb/plugin-ts.
Removed: mapper
pluginTs({ mapper: { status: 'string' } })Use printer.nodes to override a schema-type renderer, or macros to rewrite AST nodes before printing.
Removed: paramsCasing
pluginTs({ paramsCasing: 'camelcase' })Parameter properties inside the generated PathParams, QueryParams, HeaderParams, and RequestConfig types are now always camelCase. In v4 they defaulted to the original spec names, and paramsCasing: 'camelcase' opted into the new behavior. v5 makes camelCase the only option, so drop the setting.
// OpenAPI spec uses: pet_id, X-Api-Key
export type GetPetPathParams = { petId: string } // was { pet_id: string }
export type GetPetHeaderParams = { xApiKey?: string } // was { 'X-Api-Key'?: string }Changed: RequestConfig groups request input
The generated *RequestConfig type now groups every request input under { path, query, body, headers } so the client, query, and Cypress plugins all share one call shape. Each key holds the matching *PathParams, *QueryParams, *Data, or *HeaderParams type, or never when the operation has none. The path, query, and headers keys are required when the operation has a required parameter in that group, and the unused keys are typed never so passing them is a compile error.
export type GetPetRequestConfig = {
path: { petId: string } // required: the operation has a required path param
query?: GetPetQueryParams
body?: never
headers?: never
url: '/pet/{petId}'
}
export type AddPetRequestConfig = {
path?: never
query?: never
body: AddPetData
headers?: never
url: '/pet'
}The grouped object is what every generated client function, hook, and Cypress helper takes as its first argument, typed Omit<XxxRequestConfig, 'url'>. See the client plugin removal note, plugin-react-query, and plugin-cypress pages for the call-site changes.
Renamed: transformers.name
resolver.resolveTypeName replaces transformers.name.
Moved to adapterOas
dateType, integerType, unknownType, emptySchemaType, enumSuffix, and contentType moved to adapterOas. See Migration: @kubb/adapter-oas.
Changed: enum options grouped under one object
The loose enumType, enumTypeSuffix, and enumKeyCasing options now live inside one enum object. A new enum.constCasing sets the casing of the generated const. The old enumType: 'asPascalConst' is gone. Use constCasing: 'pascalCase' instead.
| v4 (old) | v5 (new) |
|---|---|
enumType: 'asConst' | enum: { type: 'asConst' } |
enumType: 'asPascalConst' | enum: { type: 'asConst', constCasing: 'pascalCase' } |
enumTypeSuffix: 'Value' | enum: { typeSuffix: 'Value' } |
enumKeyCasing: 'screamingSnakeCase' | enum: { keyCasing: 'screamingSnakeCase' } |
import { defineConfig } from '@kubb/core'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: { path: './petstore.yaml' },
output: { path: './src/gen' },
plugins: [
pluginTs({
enumType: 'asConst',
enumTypeSuffix: 'Key',
enumKeyCasing: 'none',
}),
],
})import { defineConfig } from 'kubb'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: { path: './petstore.yaml' },
output: { path: './src/gen' },
plugins: [
pluginTs({
enum: { type: 'asConst', constCasing: 'camelCase', typeSuffix: 'Key', keyCasing: 'none' },
}),
],
})TIP
Set constCasing: 'pascalCase' with typeSuffix: '' to emit a const and a type that share the schema's exact name. Most hand-written codebases use this convention, so existing annotations and value references keep working.
pluginTs({ enum: { type: 'asConst', constCasing: 'pascalCase', typeSuffix: '' } })export const VehicleType = {
Sedan: 'Sedan',
SUV: 'SUV',
} as const
export type VehicleType = (typeof VehicleType)[keyof typeof VehicleType]Generated output
Enums: object literal instead of enum
v5 emits a const-asserted object plus a *Key type union. This drops the runtime cost of a TypeScript enum and stays tree-shakeable.
export enum ParamsStatusEnum {
export enum orderParamsStatusEnum {
placed = 'placed',
approved = 'approved',
delivered = 'delivered',
}
status: ParamsStatusEnum
status: OrderParamsStatusEnumKeyEnum names are now operation-scoped (orderParamsStatusEnum, customerParamsStatusEnum) instead of suffix-deduplicated (ParamsStatusEnum, ParamsStatusEnum2), so the numeric collisions are gone. Configure enum on pluginTs when you want enum, constEnum, literal, or a different const and type casing.
int64 maps to bigint by default
adapterOas defaults integerType to 'bigint', so OpenAPI fields with format: int64 generate bigint instead of number.
- petId?: number
+ petId?: bigintSet integerType: 'number' on adapterOas to restore the previous output.
Open string unions use (string & {})
v5 writes the known TypeScript trick to keep IntelliSense suggestions.
- status?: 'accepted' | string
+ status?: 'accepted' | (string & {})JSDoc
The format suffix drops off the @type tag (@type integer | undefined, int64 becomes @type integer | undefined), since the schema already documents the format. v5 emits @example from the OpenAPI example field, and object schemas now carry an @type object tag.
Discriminated unions are factored
Fields shared by every variant of a oneOf/anyOf move into a common object:
- export type Pet =
- | { id?: number; name: string; status?: StatusEnum; ... }
- | { id?: number; name: string; status?: StatusEnum; ... }
+ export type Pet = ({ ... } | { ... }) & {
+ id?: number
+ name: string
+ status?: PetStatusEnumKey
+ ...
+ }