feat: add TypeScript 6 support#2774
feat: add TypeScript 6 support#2774benjamineckstein wants to merge 2 commits intoopenapi-ts:mainfrom
Conversation
- 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 openapi-ts#2723
👷 Deploy request for openapi-ts pending review.Visit the deploys page to approve it
|
🦋 Changeset detectedLatest commit: a749a52 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…e/Writable types for TS6 In TypeScript 6, `Date extends object` evaluates to `true` (changed from TS5). This caused `Readable<T>` and `Writable<T>` 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: openapi-ts#2723
| : T extends object | ||
| ? { [K in keyof T as NonNullable<T[K]> extends $Write<any> ? never : K]: Readable<T[K]> } | ||
| : T; | ||
| : T extends Date | RegExp | ((...args: never[]) => unknown) |
There was a problem hiding this comment.
In TypeScript 6, Date extends object now evaluates to true (it was false in TS5). Without this guard, Readable<T> would structurally expand Date fields into { toString: {}; toDateString: {}; ... } instead of preserving the Date type — making any schema containing Date fields incompatible with itself when accessed through FetchResponse.
This guard preserves built-in objects (Date, RegExp, functions) by matching them before the generic T extends object branch. It's backward compatible with TS5 since these types were never matched by T extends object there.
The Dependabot group update bumped typescript to ^6.0.2, but openapi-typescript@7.13.0 still declares peer typescript ^5.x, so npm ci fails to resolve. Revert just the typescript bump (keep the other five: @types/node, @vitest/coverage-v8, msw, oxlint, vitest) and regenerate the lockfile against 5.9.3. Add a temporary dependabot.yml ignore on typescript semver-major bumps so the same mismatch doesn't keep getting proposed. Remove the ignore once openapi-typescript ships TS 6 support (openapi-ts/openapi-typescript#2774).
* Bump the npm-deps group across 1 directory with 6 updates Bumps the npm-deps group with 5 updates in the /typescript directory: | Package | From | To | | --- | --- | --- | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.5.0` | `25.5.2` | | [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.0` | `4.1.2` | | [msw](https://github.com/mswjs/msw) | `2.12.14` | `2.13.0` | | [oxlint](https://github.com/oxc-project/oxc/tree/HEAD/npm/oxlint) | `1.56.0` | `1.58.0` | | [typescript](https://github.com/microsoft/TypeScript) | `5.9.3` | `6.0.2` | Updates `@types/node` from 25.5.0 to 25.5.2 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@vitest/coverage-v8` from 4.1.0 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/coverage-v8) Updates `msw` from 2.12.14 to 2.13.0 - [Release notes](https://github.com/mswjs/msw/releases) - [Changelog](https://github.com/mswjs/msw/blob/main/CHANGELOG.md) - [Commits](mswjs/msw@v2.12.14...v2.13.0) Updates `oxlint` from 1.56.0 to 1.58.0 - [Release notes](https://github.com/oxc-project/oxc/releases) - [Changelog](https://github.com/oxc-project/oxc/blob/main/npm/oxlint/CHANGELOG.md) - [Commits](https://github.com/oxc-project/oxc/commits/oxlint_v1.58.0/npm/oxlint) Updates `typescript` from 5.9.3 to 6.0.2 - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](microsoft/TypeScript@v5.9.3...v6.0.2) Updates `vitest` from 4.1.0 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-deps - dependency-name: "@vitest/coverage-v8" dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-deps - dependency-name: msw dependency-version: 2.13.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-deps - dependency-name: oxlint dependency-version: 1.58.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-deps - dependency-name: typescript dependency-version: 6.0.2 dependency-type: direct:development update-type: version-update:semver-major dependency-group: npm-deps - dependency-name: vitest dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-deps ... Signed-off-by: dependabot[bot] <support@github.com> * Keep typescript on 5.9.x until openapi-typescript supports TS 6 The Dependabot group update bumped typescript to ^6.0.2, but openapi-typescript@7.13.0 still declares peer typescript ^5.x, so npm ci fails to resolve. Revert just the typescript bump (keep the other five: @types/node, @vitest/coverage-v8, msw, oxlint, vitest) and regenerate the lockfile against 5.9.3. Add a temporary dependabot.yml ignore on typescript semver-major bumps so the same mismatch doesn't keep getting proposed. Remove the ignore once openapi-typescript ships TS 6 support (openapi-ts/openapi-typescript#2774). * Raise engines.node floor to >=20 (drop EOL Node 18) Node 18 reached end-of-life on 2025-04-30. Currently supported Node releases are 20 (Maintenance LTS until 2026-04-30), 22 (LTS), and 24. Lift the consumer-facing engines floor accordingly. Dev toolchain (oxlint, @inquirer/*, etc.) already requires Node 20.x or newer at the transitive level — that's fine for contributors and separate from the published SDK's runtime contract. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jeremy Daer <jeremy@37signals.com>
Summary
Add full TypeScript 6 support — not just the peer dep range, but also a fix for a TS6 behavioral change that breaks
Readable<T>andWritable<T>.Changes
Peer dep & devDependency (commit 1):
packages/openapi-typescript/package.json: widen peer dep^5.x→^5.x || ^6.xpackages/openapi-typescript-helpers/package.json: upgrade devDependency5.9.3→6.0.2Fix Readable/Writable types (commit 2):
In TypeScript 6,
Date extends objectevaluates totrue(changed from TS5). This causedReadable<T>andWritable<T>to structurally expand built-in objects likeDateinto{ toString: {}; toDateString: {}; ... }instead of preserving theDatetype.Added a guard clause for
Date | RegExp | ((...args: never[]) => unknown)before theT extends objectbranch in both type utilities, preserving built-in objects. This fix is backward compatible with TS5.Changeset: patch release for both
openapi-typescriptandopenapi-typescript-helpersValidation
pnpm run build— all 4 packages build successfullypnpm test— all 7 test suites passpnpm run lint— cleanContext
Readable<T>/Writable<T>reported by @yamafaktory in Add support for TypeScript 6 #2723