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' })
paramsCasing is no longer configurable in v5. Generated Path, Query, and Headers properties keep the exact names from the OpenAPI document.
In v4, the default behavior already preserved those names. If you used paramsCasing: 'camelcase', remove the option and update your call sites to use the OpenAPI names.
// OpenAPI spec uses: pet_id, X-Api-Key
export type GetPetPath = { pet_id: string }
export type GetPetHeaders = { 'X-Api-Key'?: string }
Changed: request input grouped under Options#
The generated *Options type groups every request input under { body, path, query, headers } so the client, query, and Cypress plugins all share one call shape. Each key holds the matching *Body, *Path, *Query, or *Headers type, or never when the operation has none. The body, 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.
::: code-group
export type GetPetOptions = {
body?: never
path: GetPetPath // required: the operation has a required path param
query?: GetPetQuery
headers?: never
}
export type AddPetOptions = {
body: AddPetBody
path?: never
query?: never
headers?: never
}
:::
The grouped *Options object is what every generated client function, hook, and Cypress helper takes as its first argument. See the client plugin removal note, plugin-react-query, and plugin-cypress pages for the call-site changes.
Renamed: transformers.name#
resolver.name replaces transformers.name. See Override a resolver for the full guide.
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' } |
::: code-group
import { defineConfig } from '@kubb/core'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: './petstore.yaml',
output: { path: './src/gen' },
plugins: [
pluginTs({
enumType: 'asConst',
enumTypeSuffix: 'Key',
enumKeyCasing: 'none',
}),
],
})
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: './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, the convention most hand-written codebases already use, so existing annotations and value references keep working.
pluginTs({ enum: { type: 'asConst', constCasing: 'pascalCase', typeSuffix: '' } })
See enum.typeSuffix for why an empty suffix merges the const and type names.
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 {
- placed = 'placed',
- approved = 'approved',
- delivered = 'delivered',
-}
+export const orderParamsStatusEnum = {
+ placed: 'placed',
+ approved: 'approved',
+ delivered: 'delivered',
+} as const
+export type OrderParamsStatusEnumKey = (typeof orderParamsStatusEnum)[keyof typeof orderParamsStatusEnum]
-status: ParamsStatusEnum
+status: OrderParamsStatusEnumKey
Enum 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?: bigint
Set 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
+ ...
+ }