You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Migrate Apache Superset's frontend from TypeScript 5.4.5 (current pin) to TypeScript 6.0.3, preserving green CI throughout by landing a chain of small, forward-compatible PRs rather than one big-bang upgrade.
Each PR in the chain:
Compiles cleanly under both TS 5.4.5 (current CI) and TS 6.0.3.
Is scoped to one package (or one cohesive group), so reviews stay reviewable.
Contains no runtime behaviour changes — only type-level adjustments, targeted as unknown as ... casts at library boundaries where our narrower types are known-safe, forward-compat widenings to match library signatures, module declarations for bundler-only assets, and similar.
Leaves master with strictly fewer TS 6.0 errors than before.
The final PR in the chain pins typescript@6.0.3 in superset-frontend/package.json and package-lock.json.
Why forward-compat
TS 6.0 tightens inference in many places (caught values as unknown, stricter JSX attribute checking, stricter forwardRef callback signatures, deprecation of baseUrl, strict property initialization enforced harder, Iterator.value as T | undefined until narrowed, etc.). Landing a single large "bump TS + fix 500+ errors" PR would:
Be unreviewable.
Touch every package simultaneously, making bisection painful if something regresses.
Create a long-running branch that constantly conflicts with master.
The forward-compat approach splits the work so each PR lands on green CI, can be merged independently, and contributes a demonstrable reduction in the TS 6.0 error count.
Rules for all PRs in this chain
No any types. Use proper TypeScript (per CLAUDE.md / project standards). Where library boundaries force widening, use targeted as unknown as <specific type> casts at the JSX/call boundary, not as any.
Prefer signature widening over casting when the fix lives in code we own (e.g. FetchRetryOptions in connection/types).
Prefer destructuring over casting when the root cause is a spread overriding an explicit attribute (e.g. Phase B's AntdEnhanced fix — {...rest} was silently overriding an explicit component={...} because IconType.component is wider than BaseIconProps['component']).
Comment any cast with a short "Forward-compat: TS 6.0 …" note explaining why the cast is safe.
Run pre-commit run on staged files before pushing. (Per CLAUDE.md — non-negotiable.) The repo's type-checking-frontend hook requires superset-ui-core/lib/ and superset-core/lib/ to be built first. Run npx tsc --build in those packages once per fresh worktree.
Stay per-package. Don't fix errors outside the package scope, even if tempted. A later phase will get them.
How to reproduce the TS 6.0 baseline in a fresh worktree
# From superset-frontend/
npm install typescript@6.0.3 --no-save
# Scope to a single package (recommended for per-phase measurement):
NODE_OPTIONS="--max-old-space-size=8192" npx tsc \
--project packages/<pkg>/tsconfig.json \
--noEmit \
--ignoreDeprecations 6.0
The --ignoreDeprecations 6.0 CLI flag silences the TS5101baseUrl deprecation warning long enough to see the real source errors. (See "Known irreducible conflict" below.)
When done, restore the pinned compiler:
npm install typescript@5.4.5 --no-save
Known irreducible conflict: baseUrl TS5101
TS 6.0 emits TS5101: Option 'baseUrl' is deprecated… against compilerOptions.baseUrl in both superset-frontend/tsconfig.json (root) and every package tsconfig that overrides it.
The standard silencer is "ignoreDeprecations": "6.0" in tsconfig.json. However, TS 5.4.5 only accepts "5.0" and rejects "6.0" with Invalid value for --ignoreDeprecations."5.0" does not silence TS 6.0's own deprecations.
Dropping the per-package baseUrl override does not help: TS 6.0 still emits TS5101 at the extends line because the option is inherited.
Decision: This is a config-level issue, not a per-package issue. It will be handled in a dedicated "root tsconfig cleanup" PR (see below), likely simultaneously with the final TS 6.0.3 pin. Individual per-package PRs ignore it.
Phase breakdown
Dependency order (leaf → app). Phases B and C are scoped per-package; later phases may batch small leaves.
Phase A — measurement/scaffolding (not a PR) ✅
Initial exploration on a throwaway branch. Established the per-phase forward-compat approach, identified the TS5101 conflict above, catalogued the rough shape of errors per package. Superseded by the phase PRs; nothing to merge.
Phase B — packages/superset-ui-core ✅ PR open: #39535
Status: In review. 15 files changed, +190/-45 lines. 24+ TS 6.0 errors in scope → 0.
Fix categories applied (useful reference for later phases):
antd sorter / filter / handler boundary: as unknown as BaseOptionType | DefaultOptionType (for sorters), as unknown as SelectHandler<...> (for deselect/select), as unknown as TableProps<object>['...'] (for Table props). Our handlers read only fields that always exist on the narrower type.
IconType.component spread override: destructure the wider-typed component out of spread so explicit JSX attribute wins.
react-resize-detector 6.0 callback: accept width?: number, default missing to 0.
src/theme/Theme.tsx: theme!: SupersetTheme and private antdConfig!: AntdThemeConfig (definite-assignment; both assigned via setConfig() in constructor).
types/external.d.ts: declare module '@fontsource/*' for CSS side-effect imports in theme/GlobalStyles.tsx.
Branch: ts6-migration/phase-c-superset-core
Phase E — small leaf packages (can run in parallel with B/C review) 📋
Scope:packages/generator-superset + packages/superset-ui-switchboard. Both have no Superset-internal dependencies, so Phase E can branch off bare master without any cherry-picking or stacking.
Measured TS 6.0 errors:
generator-superset: 0 source errors. Likely becomes part of the config cleanup PR (just covered by the root-level type-check passing).
Fix pattern: add ! definite-assignment assertions (same as Phase C Theme.tsx), assuming each field is assigned before first use. Read the constructor and start() method to confirm.
Branching:ts6-migration/phase-e-small-leaves off origin/master.
Phase D — packages/superset-ui-chart-controls 📋 (blocked on B)
Must wait for Phase B (#39535) to merge. Chart-controls depends on @superset-ui/core (peer dep) and @apache-superset/core (direct dep). Until B lands, ui-core's composite lib/ can't build cleanly under TS 6.0, which produces 55× spurious TS6305 errors plus cascading any types in chart-controls. Once B lands, the measurement clears up.
Current (pre-B-merge) TS 6.0 measurement, for reference only:
22 × TS7006 (implicit any — mostly parameter types on callbacks that were previously inferred through ui-core's types)
19 × TS2322 (type mismatches — likely similar boundary issues to Phase B)
1 × TS2538 (shared-controls/customControls.tsx:168 — Type 'unknown' cannot be used as an index type)
Many of these TS7006/TS2322 errors likely disappear once B's fixes narrow ui-core's exported types properly. Re-measure after B merges before fixing.
Branch ts6-migration/phase-d-superset-ui-chart-controls off updated master.
Install TS 6.0.3, re-measure. Expect the number of real errors to drop significantly.
Fix remaining errors using the Phase B fix-category playbook above.
Downgrade to TS 5.4.5, pre-commit run, commit, push, PR.
Phase F — superset-frontend/src/ (main app) 📋 (blocked on B, C, D)
The big one. Consumes everything above. Save for last.
Approach: same as Phase D but scoped to the main app. Re-measure after D lands — many errors in the app are cascaded from package types that D will fix. Expect the largest raw file count; plan to split this into sub-phases (e.g. F1: src/explore, F2: src/dashboard, F3: src/SqlLab, F4: everything else) if the diff gets unreviewable.
Migrate the root superset-frontend/tsconfig.json off baseUrl (paths can resolve relative to the tsconfig itself in modern TS), OR add "ignoreDeprecations": "6.0" if staying on baseUrl a bit longer. The migration-off-baseUrl path is preferred; ignoreDeprecations just kicks the can to TS 7.0.
Pin typescript@6.0.3 in superset-frontend/package.json and regenerate package-lock.json.
Run the full monorepo npm run type on TS 6.0.3 and confirm zero errors.
Document the upgrade in UPDATING.md.
Session-restart prompt template (for future Claude sessions)
If this work resumes in a new session, the agent can pick up any remaining phase with:
I'm continuing the TypeScript 5.4 → 6.0 migration tracked in [this issue link]. The goal is forward-compatible fixes that compile under both TS 5.4.5 (current CI pin) and TS 6.0.3, scoped per-package. Please read the tracking issue for full context, rules, and the fix-category playbook from Phase B. Then pick up Phase — [package name]. Follow the approach under that phase in the issue. Do not touch files outside that package. When done, run pre-commit run, open a PR titled chore(<package>): forward-compat fixes for TypeScript 6.0, and update this issue's checklist.
Goal
Migrate Apache Superset's frontend from TypeScript 5.4.5 (current pin) to TypeScript 6.0.3, preserving green CI throughout by landing a chain of small, forward-compatible PRs rather than one big-bang upgrade.
Each PR in the chain:
as unknown as ...casts at library boundaries where our narrower types are known-safe, forward-compat widenings to match library signatures, module declarations for bundler-only assets, and similar.The final PR in the chain pins
typescript@6.0.3insuperset-frontend/package.jsonandpackage-lock.json.Why forward-compat
TS 6.0 tightens inference in many places (caught values as
unknown, stricter JSX attribute checking, stricterforwardRefcallback signatures, deprecation ofbaseUrl, strict property initialization enforced harder,Iterator.valueasT | undefineduntil narrowed, etc.). Landing a single large "bump TS + fix 500+ errors" PR would:The forward-compat approach splits the work so each PR lands on green CI, can be merged independently, and contributes a demonstrable reduction in the TS 6.0 error count.
Rules for all PRs in this chain
anytypes. Use proper TypeScript (perCLAUDE.md/ project standards). Where library boundaries force widening, use targetedas unknown as <specific type>casts at the JSX/call boundary, notas any.FetchRetryOptionsinconnection/types).AntdEnhancedfix —{...rest}was silently overriding an explicitcomponent={...}becauseIconType.componentis wider thanBaseIconProps['component']).pre-commit runon staged files before pushing. (PerCLAUDE.md— non-negotiable.) The repo'stype-checking-frontendhook requiressuperset-ui-core/lib/andsuperset-core/lib/to be built first. Runnpx tsc --buildin those packages once per fresh worktree.How to reproduce the TS 6.0 baseline in a fresh worktree
The
--ignoreDeprecations 6.0CLI flag silences theTS5101baseUrldeprecation warning long enough to see the real source errors. (See "Known irreducible conflict" below.)When done, restore the pinned compiler:
Known irreducible conflict:
baseUrlTS5101TS5101: Option 'baseUrl' is deprecated…againstcompilerOptions.baseUrlin bothsuperset-frontend/tsconfig.json(root) and every package tsconfig that overrides it."ignoreDeprecations": "6.0"intsconfig.json. However, TS 5.4.5 only accepts"5.0"and rejects"6.0"withInvalid value for --ignoreDeprecations."5.0"does not silence TS 6.0's own deprecations.baseUrloverride does not help: TS 6.0 still emits TS5101 at theextendsline because the option is inherited.Phase breakdown
Dependency order (leaf → app). Phases B and C are scoped per-package; later phases may batch small leaves.
Phase A — measurement/scaffolding (not a PR) ✅
Initial exploration on a throwaway branch. Established the per-phase forward-compat approach, identified the TS5101 conflict above, catalogued the rough shape of errors per package. Superseded by the phase PRs; nothing to merge.
Phase B —
packages/superset-ui-core✅ PR open: #39535Status: In review. 15 files changed, +190/-45 lines. 24+ TS 6.0 errors in scope → 0.
Fix categories applied (useful reference for later phases):
forwardRefcallback refs:RefObject<T>→ForwardedRef<T>; addtypeof ref !== 'function'guard beforeref.current = ....as unknown as BaseOptionType | DefaultOptionType(for sorters),as unknown as SelectHandler<...>(for deselect/select),as unknown as TableProps<object>['...'](for Table props). Our handlers read only fields that always exist on the narrower type.IconType.componentspread override: destructure the wider-typedcomponentout of spread so explicit JSX attribute wins.react-resize-detector6.0 callback: acceptwidth?: number, default missing to0.FetchRetryOptions: widenretryDelay/retryOnto acceptError | null/Response | null(matchesfetch-retry).catch (caught)renaming + narrow viaParameters<typeof getClientErrorObject>[0]for TS 6.0'sunknowndefault.Mapiterator.value: guard!== undefinedbeforeMap#delete.InteractiveTableUtils.columnRef = nullfor strict property init.declare module '*.css'intypes/assets.d.ts.Branch:
ts6-migration/phase-b-superset-ui-corePhase C —
packages/superset-core✅ PR open: #39537Status: In review. 2 files changed, +13/-2 lines. 9 TS 6.0 source errors (7× TS2882, 2× TS2564) → 0.
Fixes:
src/theme/Theme.tsx:theme!: SupersetThemeandprivate antdConfig!: AntdThemeConfig(definite-assignment; both assigned viasetConfig()in constructor).types/external.d.ts:declare module '@fontsource/*'for CSS side-effect imports intheme/GlobalStyles.tsx.Branch:
ts6-migration/phase-c-superset-corePhase E — small leaf packages (can run in parallel with B/C review) 📋
Scope:
packages/generator-superset+packages/superset-ui-switchboard. Both have no Superset-internal dependencies, so Phase E can branch off bare master without any cherry-picking or stacking.Measured TS 6.0 errors:
generator-superset: 0 source errors. Likely becomes part of the config cleanup PR (just covered by the root-level type-check passing).superset-ui-switchboard: 3 × TS2564 (strict property init):src/switchboard.ts:91—portsrc/switchboard.ts:100—debugModesrc/switchboard.ts:102—isInitialisedFix pattern: add
!definite-assignment assertions (same as Phase CTheme.tsx), assuming each field is assigned before first use. Read the constructor andstart()method to confirm.Expected PR size: ~1 file, ~3-line change. Title:
chore(superset-ui-switchboard): forward-compat fixes for TypeScript 6.0.Branching:
ts6-migration/phase-e-small-leavesofforigin/master.Phase D —
packages/superset-ui-chart-controls📋 (blocked on B)Must wait for Phase B (#39535) to merge. Chart-controls depends on
@superset-ui/core(peer dep) and@apache-superset/core(direct dep). Until B lands, ui-core's compositelib/can't build cleanly under TS 6.0, which produces 55× spurious TS6305 errors plus cascadinganytypes in chart-controls. Once B lands, the measurement clears up.Current (pre-B-merge) TS 6.0 measurement, for reference only:
any— mostly parameter types on callbacks that were previously inferred through ui-core's types)shared-controls/customControls.tsx:168—Type 'unknown' cannot be used as an index type)Many of these TS7006/TS2322 errors likely disappear once B's fixes narrow ui-core's exported types properly. Re-measure after B merges before fixing.
Approach:
npx tsc --build packages/superset-ui-core).ts6-migration/phase-d-superset-ui-chart-controlsoff updated master.pre-commit run, commit, push, PR.Phase F —
superset-frontend/src/(main app) 📋 (blocked on B, C, D)The big one. Consumes everything above. Save for last.
Approach: same as Phase D but scoped to the main app. Re-measure after D lands — many errors in the app are cascaded from package types that D will fix. Expect the largest raw file count; plan to split this into sub-phases (e.g. F1:
src/explore, F2:src/dashboard, F3:src/SqlLab, F4: everything else) if the diff gets unreviewable.Config cleanup PR — root tsconfig + final pin 📋 (last)
After all package phases land:
superset-frontend/tsconfig.jsonoffbaseUrl(paths can resolve relative to the tsconfig itself in modern TS), OR add"ignoreDeprecations": "6.0"if staying onbaseUrla bit longer. The migration-off-baseUrl path is preferred;ignoreDeprecationsjust kicks the can to TS 7.0.typescript@6.0.3insuperset-frontend/package.jsonand regeneratepackage-lock.json.npm run typeon TS 6.0.3 and confirm zero errors.UPDATING.md.Session-restart prompt template (for future Claude sessions)
If this work resumes in a new session, the agent can pick up any remaining phase with:
PR checklist
packages/superset-ui-core— chore(superset-ui-core): forward-compat fixes for TypeScript 6.0 (Phase B) #39535packages/superset-core— chore(superset-core): forward-compat fixes for TypeScript 6.0 - Phase C #39537packages/superset-ui-switchboard(+generator-supersetif any errors appear)packages/superset-ui-chart-controlssuperset-frontend/src/(may be split F1/F2/…)baseUrlmigration +typescript@6.0.3pin +UPDATING.mdentryWorktree layout (current sessions)
ts6-migration/phase-b-superset-ui-core— Phase B PR branchts6-migration/phase-c-superset-core— Phase C PR branch