Description
Enable TypeScript strict mode incrementally across the entire core-web Nx workspace, one project at a time, rather than a big-bang global strict: true.
Today core-web/tsconfig.base.json has "strict": false, and it stays that way — the rollout never flips it globally. Each project opts in via its own tsconfig.json, keeping every PR small and reviewable.
The rollout follows the project dependency graph bottom-up (leaf libraries first, applications last). When a project is activated, all of its internal dependencies are already strict, so the type errors surfaced are genuinely its own instead of leaked any from upstream.
Approach (updated)
The original plan was to use typescript-strict-plugin with an opt-in paths list. That approach was dropped. The bootstrap issue (#35933) was closed without the plugin ever landing — it is absent from package.json, pnpm-lock.yaml, and main — and the first merged rollout PR (#36879, dotcms-models) instead used per-project tsconfig.json flags. That is now the established pattern:
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
There is no tsc-strict script and no // @ts-strict-ignore escape hatch. Sub-issues still referencing either are stale — ignore those acceptance criteria.
What enforces strict: for Rollup libraries that emit declarations ("declaration": true), @rollup/plugin-typescript is in the build chain and reports type errors, so the existing build target is the gate — CI runs nx run-many -t build via the build-test execution in core-web/pom.xml. Angular libraries typecheck through ng-packagr. Vite-based projects are the exception: their builds use esbuild and skip type checking, which is why the Nx Vite plugin infers a separate typecheck target for them. Note that lint does not catch type errors — ESLint reports lint rules, not TS diagnostics.
See core-web/CLAUDE.md → "TypeScript Strict Mode" for the per-project procedure.
This Epic tracks one task per TS project (42 total), each its own small PR, executed in strict dependency order.
Excluded from scope: dotcms-scss (SCSS only), dotcms-ui-e2e (e2e), mcp-server, and the empty root core-web project.
Removed from the rollout — dead libraries
Two projects were dropped after investigation showed they are dead code that does not compile. Removal is tracked in #36950:
| Project |
Issue |
Why |
dotcms |
#35936 (closed) |
Legacy initDotCMS SDK. 0 dependents, tagged skip:build/lint/test, broken dotcms-models import, last npm publish 2022-10-10. Superseded by @dotcms/client. |
dot-layout-grid |
#35937 (closed) |
Legacy NgGrid grid. 0 dependents, no build target at all, imports ComponentFactoryResolver (removed from Angular), peer deps pinned to Angular 6/7. Last consumer deleted 2024-08-22. Superseded by GridStack in libs/template-builder. |
Process note: the sub-issues were generated from the Nx dependency graph without checking whether each project was still alive. An audit of all 44 confirmed the problem is bounded to these two — every other library in the rollout has real dependents — but future automated rollouts should verify liveness before generating issues.
Progress
| Issue |
Project |
Outcome |
| #35934 |
dotcms-models |
Done — PR #36879 (established the per-project pattern) |
| #35935 |
sdk-types |
Already compliant before the epic; PR #36957 shipped the docs |
| #35936 |
dotcms |
Dead library — closed, removal tracked in #36950 |
| #35937 |
dot-layout-grid |
Dead library — closed, removal tracked in #36950 |
| #35938 |
sdk-create-app |
Done — PR #36957 (2 errors) |
| #35939 |
dotcms-js |
Done — PR #36957 (38 errors) |
| #35940 |
utils |
Done — PR #36957 (32 lib + 17 spec errors) |
| #35941 |
sdk-uve |
Already compliant before the epic — closed, no diff |
| #35942 |
sdk-client |
Already compliant before the epic — closed, no diff |
| #35943 |
dotcms-webcomponents |
Groundwork only in PR #36957 — Stencil decorator members prepared; strict still off, ~250 errors across 38 files remain |
| #35944 |
utils-testing |
Done — PR #36957 (flags were present but inert: a stale types: ["jasmine"] aborted all type checking) |
| #35945 |
sdk-react |
Done — PR #36957 (14 TS4111 accesses; build verified as a real gate by negative test) |
Enforcement is uneven and worth tracking. Only some of these projects have CI that actually verifies the flags.
- Enforced through their build:
sdk-types, sdk-create-app, sdk-uve, sdk-client and sdk-react — the Nx rollup, esbuild and tsc executors all type-check.
- Declared but unverified:
dotcms-js, utils and utils-testing have no build target and are tag-excluded from lint and test, so their flags are documentation only — a regression there would not be caught. Worth a follow-up decision on whether to add typecheck targets for that class of project.
- The opposite case:
dotcms-webcomponents has no skip:build, so Stencil type-checks it on every PR. There the gate is real and strict is all-or-nothing — it cannot be switched on until the error count reaches zero.
A related trap found along the way: a tsconfig that names a types entry which is not installed makes tsc emit TS2688 and stop before semantic checking, so it reports one error no matter what the code does. That is what hid utils-testing's real errors, and it means a stable error count across a change proves nothing in that situation.
Execution order (high level)
Layer 0 dotcms-models, sdk-types, ...
Layer 1 dotcms-js, utils, sdk-uve, ...
Layer 2 utils-testing, sdk-react, ...
Layer 3 data-access, ...
Layer 4 global-store
Layer 5 ui
Layer 6 block-editor + portlets-*
Layer 7 edit-ema-ui, portlets-content-drive
Layer 8 edit-content
Layer 9 portlets-edit-ema-portlet
Layer 10 dotcms-ui (app)
The full ordered list lives in the sub-issues, numbered [NN/44] (numbering kept as originally generated; two of those numbers are now closed as not applicable).
Desired Outcome
- All in-scope
core-web projects compile clean under strict with zero errors.
- Every strict project is actually enforced by a CI target (build or
typecheck) — strict flags that nothing verifies are worthless.
- No regressions:
nx affected -t build,lint stays green throughout.
- New
any usage trends toward zero.
Target Personas
Links
Description
Enable TypeScript
strictmode incrementally across the entirecore-webNx workspace, one project at a time, rather than a big-bang globalstrict: true.Today
core-web/tsconfig.base.jsonhas"strict": false, and it stays that way — the rollout never flips it globally. Each project opts in via its owntsconfig.json, keeping every PR small and reviewable.The rollout follows the project dependency graph bottom-up (leaf libraries first, applications last). When a project is activated, all of its internal dependencies are already strict, so the type errors surfaced are genuinely its own instead of leaked
anyfrom upstream.Approach (updated)
The original plan was to use
typescript-strict-pluginwith an opt-inpathslist. That approach was dropped. The bootstrap issue (#35933) was closed without the plugin ever landing — it is absent frompackage.json,pnpm-lock.yaml, andmain— and the first merged rollout PR (#36879,dotcms-models) instead used per-projecttsconfig.jsonflags. That is now the established pattern:There is no
tsc-strictscript and no// @ts-strict-ignoreescape hatch. Sub-issues still referencing either are stale — ignore those acceptance criteria.What enforces strict: for Rollup libraries that emit declarations (
"declaration": true),@rollup/plugin-typescriptis in the build chain and reports type errors, so the existingbuildtarget is the gate — CI runsnx run-many -t buildvia thebuild-testexecution incore-web/pom.xml. Angular libraries typecheck throughng-packagr. Vite-based projects are the exception: their builds use esbuild and skip type checking, which is why the Nx Vite plugin infers a separatetypechecktarget for them. Note thatlintdoes not catch type errors — ESLint reports lint rules, not TS diagnostics.See
core-web/CLAUDE.md→ "TypeScript Strict Mode" for the per-project procedure.This Epic tracks one task per TS project (42 total), each its own small PR, executed in strict dependency order.
Excluded from scope:
dotcms-scss(SCSS only),dotcms-ui-e2e(e2e),mcp-server, and the empty rootcore-webproject.Removed from the rollout — dead libraries
Two projects were dropped after investigation showed they are dead code that does not compile. Removal is tracked in #36950:
dotcmsinitDotCMSSDK. 0 dependents, taggedskip:build/lint/test, brokendotcms-modelsimport, last npm publish 2022-10-10. Superseded by@dotcms/client.dot-layout-gridNgGridgrid. 0 dependents, nobuildtarget at all, importsComponentFactoryResolver(removed from Angular), peer deps pinned to Angular 6/7. Last consumer deleted 2024-08-22. Superseded by GridStack inlibs/template-builder.Process note: the sub-issues were generated from the Nx dependency graph without checking whether each project was still alive. An audit of all 44 confirmed the problem is bounded to these two — every other library in the rollout has real dependents — but future automated rollouts should verify liveness before generating issues.
Progress
dotcms-modelssdk-typesdotcmsdot-layout-gridsdk-create-appdotcms-jsutilssdk-uvesdk-clientdotcms-webcomponentsutils-testingtypes: ["jasmine"]aborted all type checking)sdk-reactTS4111accesses; build verified as a real gate by negative test)Enforcement is uneven and worth tracking. Only some of these projects have CI that actually verifies the flags.
sdk-types,sdk-create-app,sdk-uve,sdk-clientandsdk-react— the Nx rollup, esbuild and tsc executors all type-check.dotcms-js,utilsandutils-testinghave nobuildtarget and are tag-excluded from lint and test, so their flags are documentation only — a regression there would not be caught. Worth a follow-up decision on whether to addtypechecktargets for that class of project.dotcms-webcomponentshas noskip:build, so Stencil type-checks it on every PR. There the gate is real and strict is all-or-nothing — it cannot be switched on until the error count reaches zero.A related trap found along the way: a tsconfig that names a
typesentry which is not installed makestscemitTS2688and stop before semantic checking, so it reports one error no matter what the code does. That is what hidutils-testing's real errors, and it means a stable error count across a change proves nothing in that situation.Execution order (high level)
The full ordered list lives in the sub-issues, numbered
[NN/44](numbering kept as originally generated; two of those numbers are now closed as not applicable).Desired Outcome
core-webprojects compile clean understrictwith zero errors.typecheck) — strict flags that nothing verifies are worthless.nx affected -t build,lintstays green throughout.anyusage trends toward zero.Target Personas
Links
nx graph.dotcms-models) — per-project tsconfig flags.