From 7bc63d0c78c6861b3bae3a763b5d960fcb1c45b1 Mon Sep 17 00:00:00 2001 From: "benjamin.eckstein" Date: Wed, 15 Apr 2026 10:44:17 +0200 Subject: [PATCH 1/2] feat(openapi-typescript): add TypeScript 6 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Widen peer dep: `^5.x` → `^5.x || ^6.x` - Upgrade devDependency in openapi-typescript-helpers: 5.9.3 → 6.0.2 - Build, tests, and lint all pass with TS6 - No code changes needed Closes #2723 --- .changeset/widen-typescript-peer-dep.md | 5 ++ .../openapi-typescript-helpers/package.json | 2 +- packages/openapi-typescript/package.json | 2 +- pnpm-lock.yaml | 89 ++++++++++++++----- 4 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 .changeset/widen-typescript-peer-dep.md diff --git a/.changeset/widen-typescript-peer-dep.md b/.changeset/widen-typescript-peer-dep.md new file mode 100644 index 000000000..1df4cfe9e --- /dev/null +++ b/.changeset/widen-typescript-peer-dep.md @@ -0,0 +1,5 @@ +--- +"openapi-typescript": patch +--- + +feat(openapi-typescript): add TypeScript 6 support diff --git a/packages/openapi-typescript-helpers/package.json b/packages/openapi-typescript-helpers/package.json index 13d34b53f..5ece4d565 100644 --- a/packages/openapi-typescript-helpers/package.json +++ b/packages/openapi-typescript-helpers/package.json @@ -34,6 +34,6 @@ "lint:ts": "tsc --noEmit" }, "devDependencies": { - "typescript": "5.9.3" + "typescript": "6.0.2" } } diff --git a/packages/openapi-typescript/package.json b/packages/openapi-typescript/package.json index 2b322a039..5fbc38ea2 100644 --- a/packages/openapi-typescript/package.json +++ b/packages/openapi-typescript/package.json @@ -59,7 +59,7 @@ "version": "pnpm run build" }, "peerDependencies": { - "typescript": "^5.x" + "typescript": "^5.x || ^6.x" }, "dependencies": { "@redocly/openapi-core": "^1.34.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 169a744de..6bc988b3b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -67,7 +67,7 @@ importers: version: 7.3.1(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.2) vitepress: specifier: 1.6.4 - version: 1.6.4(@algolia/client-search@5.48.0)(@types/node@25.6.0)(@types/react@18.3.28)(axios@1.15.0)(change-case@5.4.4)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0)(typescript@5.9.3) + version: 1.6.4(@algolia/client-search@5.48.0)(@types/node@25.6.0)(@types/react@18.3.28)(axios@1.15.0)(change-case@5.4.4)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0)(typescript@6.0.2) packages/openapi-fetch: dependencies: @@ -224,7 +224,7 @@ importers: version: 9.6.1 msw: specifier: 2.13.3 - version: 2.13.3(@types/node@25.6.0)(typescript@5.9.3) + version: 2.13.3(@types/node@25.6.0)(typescript@6.0.2) openapi-fetch: specifier: workspace:^ version: link:../openapi-fetch @@ -287,8 +287,8 @@ importers: packages/openapi-typescript-helpers: devDependencies: typescript: - specifier: 5.9.3 - version: 5.9.3 + specifier: 6.0.2 + version: 6.0.2 packages: @@ -4239,6 +4239,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + engines: {node: '>=14.17'} + hasBin: true + ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} @@ -6070,10 +6075,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@25.6.0))(vue@3.5.27(typescript@5.9.3))': + '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@25.6.0))(vue@3.5.27(typescript@6.0.2))': dependencies: vite: 5.4.21(@types/node@25.6.0) - vue: 3.5.27(typescript@5.9.3) + vue: 3.5.27(typescript@6.0.2) '@vitejs/plugin-vue@5.2.4(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': dependencies: @@ -6222,24 +6227,30 @@ snapshots: '@vue/shared': 3.5.27 vue: 3.5.27(typescript@5.9.3) + '@vue/server-renderer@3.5.27(vue@3.5.27(typescript@6.0.2))': + dependencies: + '@vue/compiler-ssr': 3.5.27 + '@vue/shared': 3.5.27 + vue: 3.5.27(typescript@6.0.2) + '@vue/shared@3.5.27': {} '@vue/tsconfig@0.5.1': {} - '@vueuse/core@12.8.2(typescript@5.9.3)': + '@vueuse/core@12.8.2(typescript@6.0.2)': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 12.8.2 - '@vueuse/shared': 12.8.2(typescript@5.9.3) - vue: 3.5.27(typescript@5.9.3) + '@vueuse/shared': 12.8.2(typescript@6.0.2) + vue: 3.5.27(typescript@6.0.2) transitivePeerDependencies: - typescript - '@vueuse/integrations@12.8.2(axios@1.15.0)(change-case@5.4.4)(focus-trap@7.8.0)(typescript@5.9.3)': + '@vueuse/integrations@12.8.2(axios@1.15.0)(change-case@5.4.4)(focus-trap@7.8.0)(typescript@6.0.2)': dependencies: - '@vueuse/core': 12.8.2(typescript@5.9.3) - '@vueuse/shared': 12.8.2(typescript@5.9.3) - vue: 3.5.27(typescript@5.9.3) + '@vueuse/core': 12.8.2(typescript@6.0.2) + '@vueuse/shared': 12.8.2(typescript@6.0.2) + vue: 3.5.27(typescript@6.0.2) optionalDependencies: axios: 1.15.0 change-case: 5.4.4 @@ -6249,9 +6260,9 @@ snapshots: '@vueuse/metadata@12.8.2': {} - '@vueuse/shared@12.8.2(typescript@5.9.3)': + '@vueuse/shared@12.8.2(typescript@6.0.2)': dependencies: - vue: 3.5.27(typescript@5.9.3) + vue: 3.5.27(typescript@6.0.2) transitivePeerDependencies: - typescript @@ -7537,6 +7548,32 @@ snapshots: typescript: 5.9.3 transitivePeerDependencies: - '@types/node' + optional: true + + msw@2.13.3(@types/node@25.6.0)(typescript@6.0.2): + dependencies: + '@inquirer/confirm': 5.1.21(@types/node@25.6.0) + '@mswjs/interceptors': 0.41.2 + '@open-draft/deferred-promise': 2.2.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.12.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.11.7 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.0 + type-fest: 5.4.3 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 6.0.2 + transitivePeerDependencies: + - '@types/node' muggle-string@0.4.1: {} @@ -8465,6 +8502,8 @@ snapshots: typescript@5.9.3: {} + typescript@6.0.2: {} + ufo@1.6.3: {} uglify-js@3.19.3: @@ -8629,7 +8668,7 @@ snapshots: optionalDependencies: vite: 7.3.1(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.8.2) - vitepress@1.6.4(@algolia/client-search@5.48.0)(@types/node@25.6.0)(@types/react@18.3.28)(axios@1.15.0)(change-case@5.4.4)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0)(typescript@5.9.3): + vitepress@1.6.4(@algolia/client-search@5.48.0)(@types/node@25.6.0)(@types/react@18.3.28)(axios@1.15.0)(change-case@5.4.4)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0)(typescript@6.0.2): dependencies: '@docsearch/css': 3.8.2 '@docsearch/js': 3.8.2(@algolia/client-search@5.48.0)(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0) @@ -8638,17 +8677,17 @@ snapshots: '@shikijs/transformers': 2.5.0 '@shikijs/types': 2.5.0 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@25.6.0))(vue@3.5.27(typescript@5.9.3)) + '@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@25.6.0))(vue@3.5.27(typescript@6.0.2)) '@vue/devtools-api': 7.7.9 '@vue/shared': 3.5.27 - '@vueuse/core': 12.8.2(typescript@5.9.3) - '@vueuse/integrations': 12.8.2(axios@1.15.0)(change-case@5.4.4)(focus-trap@7.8.0)(typescript@5.9.3) + '@vueuse/core': 12.8.2(typescript@6.0.2) + '@vueuse/integrations': 12.8.2(axios@1.15.0)(change-case@5.4.4)(focus-trap@7.8.0)(typescript@6.0.2) focus-trap: 7.8.0 mark.js: 8.11.1 minisearch: 7.2.0 shiki: 2.5.0 vite: 5.4.21(@types/node@25.6.0) - vue: 3.5.27(typescript@5.9.3) + vue: 3.5.27(typescript@6.0.2) optionalDependencies: postcss: 8.5.6 transitivePeerDependencies: @@ -8724,6 +8763,16 @@ snapshots: optionalDependencies: typescript: 5.9.3 + vue@3.5.27(typescript@6.0.2): + dependencies: + '@vue/compiler-dom': 3.5.27 + '@vue/compiler-sfc': 3.5.27 + '@vue/runtime-dom': 3.5.27 + '@vue/server-renderer': 3.5.27(vue@3.5.27(typescript@6.0.2)) + '@vue/shared': 3.5.27 + optionalDependencies: + typescript: 6.0.2 + w3c-xmlserializer@4.0.0: dependencies: xml-name-validator: 4.0.0 From a749a529594f8d976876b291fe53e76cda5b45fb Mon Sep 17 00:00:00 2001 From: "benjamin.eckstein" Date: Wed, 15 Apr 2026 10:49:35 +0200 Subject: [PATCH 2/2] fix(openapi-typescript-helpers): preserve built-in objects in Readable/Writable types for TS6 In TypeScript 6, `Date extends object` evaluates to `true` (changed from TS5). This caused `Readable` and `Writable` to structurally expand Date, RegExp, and function fields instead of preserving them. Add a guard clause for built-in objects (Date, RegExp, functions) before the `T extends object` branch in both type utilities. Ref: #2723 --- .changeset/widen-typescript-peer-dep.md | 6 +++++- .../openapi-typescript-helpers/src/index.ts | 20 +++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.changeset/widen-typescript-peer-dep.md b/.changeset/widen-typescript-peer-dep.md index 1df4cfe9e..50777428e 100644 --- a/.changeset/widen-typescript-peer-dep.md +++ b/.changeset/widen-typescript-peer-dep.md @@ -1,5 +1,9 @@ --- "openapi-typescript": patch +"openapi-typescript-helpers": patch --- -feat(openapi-typescript): add TypeScript 6 support +feat: add TypeScript 6 support + +- Widen peer dep to `^5.x || ^6.x` +- Fix `Readable` and `Writable` to preserve built-in objects (Date, RegExp, functions) that now match `extends object` in TS6 diff --git a/packages/openapi-typescript-helpers/src/index.ts b/packages/openapi-typescript-helpers/src/index.ts index 391e0a694..0db604a35 100644 --- a/packages/openapi-typescript-helpers/src/index.ts +++ b/packages/openapi-typescript-helpers/src/index.ts @@ -223,9 +223,11 @@ export type Readable = ? Readable : T extends (infer E)[] ? Readable[] - : T extends object - ? { [K in keyof T as NonNullable extends $Write ? never : K]: Readable } - : T; + : T extends Date | RegExp | ((...args: never[]) => unknown) + ? T + : T extends object + ? { [K in keyof T as NonNullable extends $Write ? never : K]: Readable } + : T; /** * Resolve type for writing (requests): strips $Read properties, unwraps $Write @@ -240,8 +242,10 @@ export type Writable = ? Writable : T extends (infer E)[] ? Writable[] - : T extends object - ? { [K in keyof T as NonNullable extends $Read ? never : K]: Writable } & { - [K in keyof T as NonNullable extends $Read ? K : never]?: never; - } - : T; + : T extends Date | RegExp | ((...args: never[]) => unknown) + ? T + : T extends object + ? { [K in keyof T as NonNullable extends $Read ? never : K]: Writable } & { + [K in keyof T as NonNullable extends $Read ? K : never]?: never; + } + : T;