Skip to content

fix(examples): type the settings holders for Handsontable 18.1 (DEV-2727) - #281

Merged
demtario merged 2 commits into
masterfrom
fix/DEV-2727-angular-18-1-column-settings
Sep 2, 2026
Merged

fix(examples): type the settings holders for Handsontable 18.1 (DEV-2727)#281
demtario merged 2 commits into
masterfrom
fix/DEV-2727-angular-18-1-column-settings

Conversation

@demtario

@demtario demtario commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes DEV-2727. Companion backport: fix/DEV-2727-angular-18-1-column-settings-p18prod-examples/18 (same commit, cherry-picked). This PR alone does not fix ?v=18.1.0 — bucket 18 generates from the frozen branch, so master only reaches the next bucket and future branch cuts.

What broke

18.1.0 rewrote ColumnSettings in handsontable/settings.d.ts:

-export interface ColumnSettings extends Omit<GridSettings, 'data'> {
+export interface ColumnSettings extends Omit<RemoveIndexSignature<GridSettings>, 'data'> {
+    [key: string]: any;

GridSettings carries [key: string]: any, so under 18.0.0 that Omit collapsed to a bare index signature and every named column option resolved to any. Stripping the signature first makes the declared types real. dateFormat itself did not change — only whether anyone checked it.

Two starters were relying on the collapse:

  • angulargridSettings was an unannotated object literal, so dateFormat: { year: 'numeric', … } widened to { year: string } and failed against Intl.DateTimeFormatOptions at the [settings] binding. ng build is the only starter dev server that type-checks, and its failure is silent from outside: the dev server keeps serving the last good bundle and the browser console stays clean, which is why this reads as a demo that simply never renders.
  • base-webcolorRenderer declared value: string and an instance parameter of Handsontable instead of HotInstance. A column renderer was any before.

nuxt gets the same annotation preventively: hotSettings is the identical unannotated-holder shape and only escapes today because it carries no strictly-typed option and nuxt build does not type-check. Verified it has teeth — injecting autoWrapCol: 12345 now errors.

Every other starter passes its settings literal directly as a call argument or JSX/template prop, where contextual typing keeps the literals narrow. examples/example1/index.ts carries the identical dateFormat object and compiles fine.

Why the fix is not on the dateFormat line

runner/pipeline/starter-overrides.mjs (id: "angular:dateFormat") replaces that whole line per bucket at import time, asserting exactly one match on exactly one line. A cast or as const written there would be regenerated away and never ship. Annotating the holder is the only form that survives generation — and GridSettings is exported by the Angular wrapper at 16.2.0 and 17.1.0 too, so the annotation is safe at every bucket.

Lockfiles

All 16 starters say "handsontable": "latest" in package.json while their lockfiles still pinned 18.0.0 — the ERR_PNPM_OUTDATED_LOCKFILE drift 822d0820 fixed the last time, which breaks the container bake and silently pushes Tier-2 sessions onto the --no-frozen-lockfile fallback. @handsontable/pikaday is left at 1.0.0 (NEVER_REWRITE).

Note for next time: pnpm install --lockfile-only does not re-resolve a latest specifier — with the specifier unchanged pnpm considers the lockfile current and reuses the old resolution. pnpm update handsontable @handsontable/<wrapper> --lockfile-only is the command.

No generated artifacts are committed. import-starters.yml regenerates the buckets from the correct source refs once this lands.

Verification (raw pnpm throughout, no rtk)

  • examples/angular at 18.1.0: ng build red before with the exact DEV-2727 error, green after.
  • The artifact that actually ships: generated the way CI does — node pipeline/import.mjs --bucket=18 --source=<prod-examples/18 worktree>/examples --ref=prod-examples/18 — then extracted angular.json to a temp dir outside the repo. pnpm install --frozen-lockfile clean, ng build clean, pinned 18.1.0. The overlay applied angular:dateFormat, angular:data-iso, angular:data-passthrough and correctly rewrote the branch's format string to the Intl object.
  • base-web, example1, fluent-ui, mui, next.js, next-shadcn.js, react, remix, typescript, vue all build at 18.1.0. nuxt type-checks under vue-tsc (no dependency added — borrowed the vue starter's binary).
  • runner: pnpm test 940 pass / 0 fail, pnpm typecheck clean, working tree clean.

Found while testing, not fixed here

  • examples/base-web fails TS2688: Cannot find type definition file for 'node' in any isolated build. tsconfig.node.json sets "types": ["node"] but base-web has no @types/node dependency; it passes in-tree only because TypeScript walks up to the repo root's hoisted copy. The Tier-2 container works at /app with /baked/<framework>-18/ and has no such ancestor, so base-web's share/build path is likely already broken — independently of 18.1. The starter matrix misses it because it boots dev, not build. Tracked as DEV-2730.
  • @handsontable/vue3@18.1.0 declares "types": "./index.d.ts" and ships no .d.ts file at all. So HotTable is implicitly any in the vue/nuxt starters, which is why nuxt's annotation had to come from handsontable/settings rather than the wrapper. A core-repo packaging defect — DEV-2732.
  • server-examples/ has the same defect, verified. All 7 Angular frontends use the unannotated-holder shape; a scratch build of express/client-angular is green at 18.0.0 and red at 18.1.0 with the identical dateFormat.year error. Their package-lock.json files still pin 18.0.0, so nothing is broken until someone refreshes a lock. The React frontends spread {...(settings as any)} and are unaffected. DEV-2731.
  • The authoring app's own pins stay at 18.0.0 and do not self-correct: runner/apps/authoring/package.json, src/theme/presets.ts BUNDLED_VERSION, src/catalog.ts VERSION_OPTIONS / DEFAULT_VERSION.
  • @handsontable/pikaday is an unused dependency of examples/javascript (no import anywhere; also a stale allowedCommonJsDependencies entry in examples/angular/angular.json, and the NEVER_REWRITE exemption exists only for it). DEV-2733.

…727)

18.1.0 rewrote `ColumnSettings` from `Omit<GridSettings, 'data'>` to
`Omit<RemoveIndexSignature<GridSettings>, 'data'>`. Under 18.0.0 that
`Omit` collapsed against `GridSettings`'s `[key: string]: any` index
signature, so every named column option resolved to `any`. Stripping the
signature first makes the declared option types real, and two starters had
been relying on the collapse:

- angular: `gridSettings` was an unannotated object literal, so
  `dateFormat: { year: 'numeric', ... }` widened to `{ year: string }` and
  failed against `Intl.DateTimeFormatOptions` at the `[settings]` binding.
  `ng build` is the only starter dev server that type-checks, so this
  surfaced as a demo that never renders while the browser console stayed
  clean and the dev server kept serving the last good bundle.
- base-web: `colorRenderer` declared `value: string` and an instance
  parameter of `Handsontable` rather than `HotInstance`; a column
  `renderer` was `any` before.

nuxt gets the same annotation preventively: `hotSettings` is the identical
unannotated-holder shape and only escapes today because it carries no
strictly-typed option and `nuxt build` does not type-check.

The angular fix cannot live on the `dateFormat` line itself.
`pipeline/starter-overrides.mjs` (`angular:dateFormat`) replaces that whole
line per bucket at import time, so a cast written there would be
regenerated away and never ship.

Also re-resolves `handsontable` and the wrapper packages in all 16 starter
lockfiles, which still pinned 18.0.0 while every package.json says
"latest" - the ERR_PNPM_OUTDATED_LOCKFILE drift 822d082 fixed last time.
`@handsontable/pikaday` is left at 1.0.0 (NEVER_REWRITE).

Verified at 18.1.0: `ng build` red before / green after; the generated
bucket-18 angular artifact installs with --frozen-lockfile and builds
clean; base-web, example1, fluent-ui, mui, next.js, next-shadcn.js, react,
remix, typescript and vue all build; runner `pnpm test` 940 pass / 0 fail
and `pnpm typecheck` clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qunabu

qunabu commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@qunabu

qunabu commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@demtario
demtario merged commit 558ab4c into master Sep 2, 2026
6 checks passed
@demtario
demtario deleted the fix/DEV-2727-angular-18-1-column-settings branch September 2, 2026 07:59
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.

2 participants