Skip to content

chore: Upgrade to TypeScript 6.0.3 and API Extractor 7.x - #3315

Open
bc-0dp wants to merge 4 commits into
bigcommerce:masterfrom
bc-0dp:typescript-6-upgrade
Open

chore: Upgrade to TypeScript 6.0.3 and API Extractor 7.x#3315
bc-0dp wants to merge 4 commits into
bigcommerce:masterfrom
bc-0dp:typescript-6-upgrade

Conversation

@bc-0dp

@bc-0dp bc-0dp commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

What/Why?

Upgrade the SDK from TypeScript 5.8 to 6.0.3 (via a 5.9 checkpoint), ahead of the eventual TypeScript 7 (native) move. TS 6.0 is a transitional release; its breaking changes are handled here. Also migrates the declaration rollup from @microsoft/api-extractor 6.3.0 (bundled TS 3.1) to 7.58.9.

Key changes:

  • tsconfig.base.json: "ignoreDeprecations": "6.0" (silences baseUrl, moduleResolution node10, and target es5 pending the TS 7 migration) and "types": ["*"] to restore the pre-6.0 automatic @types global inclusion.
  • ts-loader now uses an explicit configFile with onlyCompileBundledFiles, so the webpack build type-checks only bundled files, not the whole repo (TS 6.0 defaults strict: true and types: []).
  • build-dts passes --rootDir .. (TS 6.0 no longer infers rootDir for the multi-package emit) and strips api-extractor 7.x export { } markers, so consumers keep importing the SDK's bare-declared types, matching the long-standing published .d.ts shape.
  • Migrated 6 api-extractor configs and the auto-export generator to the 7.x schema.
  • .npmrc legacy-peer-deps=true works around @bigcommerce/eslint-config's stale optional typescript peer (^4 || ^5); added @bigcommerce/eslint-plugin as a direct devDep so ESLint resolves it.

Reviewer note: the docs/ diff includes api-extractor 7.x numeric disambiguation renames (e.g. Omit.md becomes Omit_2.md, PaymentProviderCustomerType becomes PaymentProviderCustomer_2). Content is unchanged; only the internal collision labels differ.

Rollout/Rollback

Tooling and build-config change only. No runtime feature flags, experiments, or migrations. The published JS bundles are behavior-equivalent (Babel still targets the existing browserslist); only the .d.ts structure and build config change. Rollback is a straight revert of this branch.

Testing

  • SDK, all green under TS 6.0.3: lint (52 projects), test (core 2478 tests plus 51 other projects), build, bundle-dts, docs (587 files), build-cdn.
  • Consumer (checkout-js): typecheck output is byte-identical to the published-SDK baseline (214 pre-existing errors on its master, 0 new). TS2459 "declared locally but not exported" count is 0, confirming the export { } strip. build passes; the test suite reports 1324 pass with 2 pre-existing failures unrelated to the SDK.
  • Sandbox UAT: full checkout flow works end to end (cart, payment, order placement, order confirmation) against the TS6 build.

Note

Medium Risk
Changes affect the published .d.ts pipeline and monorepo typecheck scope; consumer typecheck was validated against checkout-js but any downstream relying on exact declaration formatting could still be sensitive.

Overview
Upgrades the monorepo from TypeScript 5.8 to 6.0.3 (with a 5.9 checkpoint) and @microsoft/api-extractor from 6.x to 7.58.9, as prep for a future TypeScript 7 move. Runtime JS is unchanged (Babel/browserslist); impact is build tooling and published .d.ts shape.

TypeScript 6 defaults (strict, empty types) are offset in tsconfig.base.json via ignoreDeprecations: "6.0" and types: ["*"]. Webpack ts-loader now uses an explicit configFile and onlyCompileBundledFiles so the bundle build type-checks only entry graphs, not the whole repo.

Declaration rollup passes --rootDir .. on tsc (TS 6 no longer infers rootDir for multi-package emit), updates six api-extractor configs plus the auto-export generator to the 7.x schema, and strips api-extractor 7’s export { } markers so consumers keep the same bare-declared import surface. hosted-form-v2 follows the same build-dts pattern.

npm/ESLint: legacy-peer-deps and a direct @bigcommerce/eslint-plugin devDep address stale TypeScript peer ranges on @bigcommerce/eslint-config. Generated docs only rename collision suffixes (e.g. Omit_2.md); content is unchanged.

Reviewed by Cursor Bugbot for commit eb1229f. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 1774427. Configure here.

Comment thread packages/hosted-form-v2/project.json
bc-0dp added 2 commits August 12, 2026 13:22
Move from TypeScript 5.8 to 6.0.3 (via a 5.9 checkpoint) and migrate the
declaration rollup from api-extractor 6.3.0 to 7.58.9.

Adjustments for TS 6.0 breaking changes:
- tsconfig.base.json: set "ignoreDeprecations": "6.0" (baseUrl,
  moduleResolution node10, target es5) and "types": ["*"] to restore the
  pre-6.0 automatic @types global inclusion.
- ts-loader now uses an explicit configFile with onlyCompileBundledFiles so
  the webpack build type-checks only bundled files, not the whole repo.
- build-dts passes --rootDir .. (TS 6.0 no longer infers rootDir) and strips
  api-extractor 7.x "export { }" markers so consumers can import the SDK's
  bare-declared types, matching the long-standing published .d.ts shape.
- Migrated 6 api-extractor configs and the auto-export generator to the 7.x
  schema.
- .npmrc legacy-peer-deps=true works around @bigcommerce/eslint-config's stale
  optional typescript peer (^4 || ^5); added @bigcommerce/eslint-plugin as a
  direct devDep so ESLint resolves it.
The two api-extractor runs were joined with a single "&", leaving the
iframe-content rollup backgrounded with no "wait". The following declaration
strip and "rm -rf ../../temp" could run before it finished, risking an
unstripped hosted-form-v2-iframe-content.d.ts or removing temp mid-read.
Add a trailing "& wait" to match the core build-dts target.
@bc-0dp
bc-0dp force-pushed the typescript-6-upgrade branch from 1aedde4 to 6e96f5e Compare August 12, 2026 11:39

@bc-maxy bc-maxy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me overall, thanks for doing it, just curious about the es5 comment

Comment thread packages/core/api-extractor/checkout-sdk.json Outdated
Comment thread package.json Outdated
es5 is deprecated in TypeScript 6.0. The target is inert for API Extractor's .d.ts-only analysis (explicit lib is set), so the rolled-up public type surface is unchanged; switching to es6 aligns with the base tsconfig and removes the deprecated option.

@bc-maxy bc-maxy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good from my side

@richapatel1510 richapatel1510 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since dist/ typings only get regenerated at release, I built this branch locally to see the v7 output before it ships. Everything's green, and the diff vs. committed typings is ~1,700 lines of harmless alias-renaming churn — the upgrade itself looks good. The only real issues are the two inline comments (perl strip deleting real exports, and & wait swallowing extractor failures). With the anchored regex, the output comes out correct.

Comment thread .npmrc Outdated
"tsc --outDir ../../temp --rootDir .. --declaration --emitDeclarationOnly",
"api-extractor run --config api-extractor/checkout-sdk.json & api-extractor run --config api-extractor/checkout-button.json & api-extractor run --config api-extractor/embedded-checkout.json & api-extractor run --config api-extractor/internal-mappers.json & wait",
"find src/generated/integrations -name 'api-extractor.json' | xargs -I {} -P 8 sh -c 'cd \"$(dirname \"{}\")\" && npx api-extractor run --config api-extractor.json'",
"find ../../dist/types -name '*.d.ts' -type f -exec perl -i -ne 'print unless /^export \\{.*\\}\\s*$/' {} +",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran build-dts on this branch to check the new output — the regex here catches more than the trailing export { }. API Extractor 7 also emits real exports in this form (no semicolon), and the raw output has export { createTimeout } in both checkout-sdk.d.ts and checkout-button.d.ts. The perl step deletes those too, so createTimeout disappears from the published typings. Funnily enough, v7 was actually fixing this — the current typings have the import but no export, and this strip reverts the fix.

Anchoring it to the empty marker fixes it:

perl -i -ne 'print unless /^export \{\s*\}\s*$/'

Same change needed in hosted-form-v2's project.json.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@richapatel1510 I think I need a bit of guidance on this one.

When I try your suggestion perl -i -ne 'print unless /^export \{\s*\}\s*$/', only 20 typedoc files are output vs 590 - any export { … } block (even export { createTimeout }) flips the entry file into explicit-export mode, so typedoc stops documenting the bare declares.

If I apply the narrow strip to the types only (a hybrid), createTimeout() gets exported and the docs stay at 590. Consumer imports are unaffected either way.

If I keep the broad strip as-is, createTimeout() isn't exported - but am I wrong in saying it's also not exported on main today?

So I'm leaning toward the hybrid. Does that work for you, or would you rather handle it differently?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @bc-0dp ,

Dug into this properly and you're right — keeping the broad strip is correct. Any surviving export { ... } statement (even from my suggested regex) flips the .d.ts out of implicit-export mode, and I confirmed with tsc that the narrow version breaks imports of most public types, while your version matches the exact surface published today. So: as-is is right, withdrawing my suggestion.

On createTimeout — confirmed it's already missing on main, so nothing for this PR. (For a follow-up: "bundledPackages": ["@bigcommerce/request-sender"] in checkout-sdk.json makes API Extractor inline it and would fix it properly.)

Comment thread packages/hosted-form-v2/project.json Outdated
build-dts: capture api-extractor PIDs and wait per-PID so a failing run surfaces a non-zero exit; previously `& wait` always exited 0 and masked extractor failures. Applies to core and hosted-form-v2.

deps: replace .npmrc legacy-peer-deps with a scoped @bigcommerce/eslint-config typescript override, which cascades to the nested eslint-plugin; drop the now-unneeded direct @bigcommerce/eslint-plugin devDep and regenerate the lockfile.

@richapatel1510 richapatel1510 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! 👏 👏
Thanks for doing this 🙇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants