Skip to content

Publish TypeScript declarations from the 4.x packages#402

Open
phillipc wants to merge 5 commits into
knockout:mainfrom
Auge19:384-publish-typescript-declarations-dts-from-the-4x-packages
Open

Publish TypeScript declarations from the 4.x packages#402
phillipc wants to merge 5 commits into
knockout:mainfrom
Auge19:384-publish-typescript-declarations-dts-from-the-4x-packages

Conversation

@phillipc

@phillipc phillipc commented Jun 4, 2026

Copy link
Copy Markdown
Member

Summary

  • publish generated types/ folders for every public packages/* workspace and both bundled builds
  • replace the old single-bundle declaration flow with a packaging-aware declaration build step and add a consumer type smoke test
  • advertise shipped declarations through types metadata and exports conditions, including preserving the extra public type surface on @tko/build.knockout and @tko/build.reference

Closes #384.

Testing

  • bun run dts
  • bun run build
  • bun run verify:types
  • bun run tsc
  • npm pack --dry-run in packages/observable
  • npm pack --dry-run in builds/knockout
  • npm pack --dry-run in builds/reference
  • bun run verify

Summary by CodeRabbit

  • New Features

    • TypeScript declaration files are now published with all public packages and bundled builds; packages advertise type entrypoints so consumers resolve shipped types.
  • Build Infrastructure

    • Build now emits per-package types, adds an automated declaration-generation script, a smoke-test consumer, and CI verification for emitted types.
  • Chores

    • Clean/ignore rules and build scripts updated to handle generated type artifacts; release metadata updated with a changeset and packaging plan.

- Introduced a `types/` directory for each package and build to publish TypeScript declaration files.
- Updated package manifests to include `types` metadata and `exports` conditions for better type resolution.
- Implemented a new build script to generate declarations and clean up generated artifacts.
- Enhanced the build process to ensure all public packages and builds have corresponding type definitions.
- Added smoke tests to verify type imports from the generated declarations.
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e4df1cf-972f-4aaa-abc9-b5ce9f9083df

📥 Commits

Reviewing files that changed from the base of the PR and between f80a552 and 29083f1.

📒 Files selected for processing (5)
  • builds/reference/src/index.ts
  • packages/builder/src/Builder.ts
  • packages/utils.jsx/src/index.ts
  • packages/utils.jsx/src/jsx.ts
  • tools/build-dts.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/utils.jsx/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • tools/build-dts.ts

📝 Walkthrough

Walkthrough

Moves declaration emit to per-workspace types/, adds tools/build-dts.ts to generate and copy .d.ts into each workspace, updates ~27 package manifests to publish and expose ./types/index.d.ts, refines builder and build entry typings, and adds CI smoke-tests and docs to verify the layout.

Changes

TypeScript Declaration Publishing

Layer / File(s) Summary
Build system and declaration configuration
tsconfig.dts.json, package.json, .gitignore, tools/build-dts.ts
Switches declaration emit to per-workspace rootDir/outDir, adds tools/build-dts.ts (discovers workspaces, runs tsc, copies emitted .d.ts into each workspace/types/), updates root scripts (dts, verify:types), and ignores generated packages/*/types/* and builds/*/types/*.
Build package types and manifests
builds/knockout/src/index.ts, builds/reference/src/index.ts, builds/knockout/package.json, builds/reference/package.json
Adds KnockoutBuildExtensions/ReferenceBuildExtensions types, refactors inline build extension objects to typed constants, and updates both build package manifests to include types/ in files, add exports['.'].types, and add top-level types fields.
Generic Builder.create type signature
packages/builder/src/Builder.ts, packages/builder/package.json
Makes Builder.create generic over additional property objects and refines its return type to KnockoutInstance & T; updates builder package manifest to ship types/ and point types entry.
Workspace package manifest updates
packages/*/package.json, builds/*/package.json (27 packages)
Consistently add types/ to files, add exports['.'].types: "./types/index.d.ts", and add a top-level types: "./types/index.d.ts" across the packages and builds to ensure consumer imports resolve shipped declarations.
JSX render API and utils
packages/utils.jsx/src/jsx.ts, packages/utils.jsx/src/index.ts
Adds render(jsx) and exported JsxRenderResult type; updates index re-exports to expose render and the JsxRenderResult type.
Type verification, smoke tests, and release documentation
tools/types-smoke/consumer.ts, tools/types-smoke/tsconfig.json, .github/workflows/lint-and-typecheck.yml, plans/2026-06-04-dts-types-layout.md, .changeset/publish-types-layout.md
Adds a TypeScript consumer smoke-test and tsconfig, CI step to run verify:types, planning documentation of the new per-workspace declaration layout, and a changeset release note describing the publishing change.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • knockout/tko#299: Overlaps on types/ wiring, packaging changes, and related DTS tooling.
  • knockout/tko#289: Previously modified package.json type-wiring (files, exports.types) that this PR applies broadly.
  • knockout/tko#227: Related edits to the builds/reference JSX render surface.

Suggested reviewers

  • brianmhunt
  • dvHuett
  • M-Kirchhoff

"🐰 Hop! Declarations at last —
Types hop into each package's nest,
From bundle wide to per-workspace rest,
Imports find them, consumers blessed."

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: publishing TypeScript declarations for the 4.x packages, which matches the primary objective of the PR.
Linked Issues check ✅ Passed The PR addresses all coding requirements from issue #384: publishes generated types/ folders for all public packages and builds, updates package.json with types metadata and exports conditions, includes declaration file generation in the build pipeline, and adds type smoke tests.
Out of Scope Changes check ✅ Passed All changes align with the linked issue objectives. Package.json updates, build script modifications, new declaration generation tooling, type exports, and smoke tests are all within scope. The comment-suggested simplifications to Builder.create and extraction of JsxRenderResult are implementation choices rather than out-of-scope additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
tools/types-smoke/consumer.ts (1)

1-14: ⚡ Quick win

Consider expanding package coverage in the smoke test.

The smoke test currently exercises only 3 packages (@tko/build.knockout, @tko/build.reference, @tko/observable) but the changeset advertises type publishing for 27 packages across binding.*, provider.*, utils.*, and other categories. Consider adding imports from a few more representative packages to increase confidence that the declaration publishing strategy works uniformly across the workspace.

🧪 Example expanded coverage
 import ko from '`@tko/build.knockout`'
 import reference from '`@tko/build.reference`'
 import { observable } from '`@tko/observable`'
+import { DataBindProvider } from '`@tko/provider.databind`'
+import { options } from '`@tko/utils`'

 const name = observable('TKO')
 const knockoutVersion: string = ko.version
 const referenceVersion: string = reference.version
 const bindingString: string = ko.expressionRewriting.preProcessBindings('text: name')
+const provider = new DataBindProvider()
+const defaultOptions = options
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/types-smoke/consumer.ts` around lines 1 - 14, Add additional
representative package imports and simple usages to the smoke test so types from
more of the 27 packages are exercised: extend the current imports (ko,
reference, observable) by importing a few packages from other groups (e.g., one
or two from binding.*, one or two from provider.*, and one or two from utils.*)
and use a small typed value from each (for example assign an exported const or
call a small factory) similar to how name, bindingString, and jsxTree are used;
keep exports (e.g., add to the exported list or create new exported consts) so
those types are included at build time and ensure you reference the actual
package names added in the file when editing consumer.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/builder/src/Builder.ts`:
- Around line 320-323: The JSDoc for the create method is stale: update the
`@return` annotation on the create<T extends object[]>(...additionalProperties: T)
method so it reflects the actual signature by documenting the return type as
KnockoutInstance & AdditionalProperties<T> (or equivalent JSDoc generics),
ensuring the doc comment references both KnockoutInstance and
AdditionalProperties<T> to match the public API and improve generated
docs/editor hints.

In `@tools/build-dts.ts`:
- Around line 22-25: The current logic assumes emitted types live under
`${workspace}/src` (emittedTypesDir, indexDeclaration) and only copies from
`/src`, which misses packages whose entry is `packages/*/index.ts`; update the
code to look for and prefer declaration files in both
`${workspace}/src/index.d.ts` and `${workspace}/index.d.ts` (check both paths
before deciding missing), and copy/type-publish from whichever exists (or both)
into `${workspace}/types`; additionally add `packages/*/index.ts` to the
tsconfig.dts.json "files"/"include" inputs so TypeScript emits root package
entry declarations (adjust the tsconfig update logic to include that glob).

In `@tools/types-smoke/tsconfig.json`:
- Around line 2-11: Add an explicit "noImplicitAny": false under
"compilerOptions" to satisfy the repo guideline while keeping "strict": true;
update the tsconfig.json's compilerOptions block (where "strict", "target",
"module", "moduleResolution", "types", and "lib" are defined) to include
noImplicitAny: false so TypeScript remains strict but allows implicit any per
guideline.

---

Nitpick comments:
In `@tools/types-smoke/consumer.ts`:
- Around line 1-14: Add additional representative package imports and simple
usages to the smoke test so types from more of the 27 packages are exercised:
extend the current imports (ko, reference, observable) by importing a few
packages from other groups (e.g., one or two from binding.*, one or two from
provider.*, and one or two from utils.*) and use a small typed value from each
(for example assign an exported const or call a small factory) similar to how
name, bindingString, and jsxTree are used; keep exports (e.g., add to the
exported list or create new exported consts) so those types are included at
build time and ensure you reference the actual package names added in the file
when editing consumer.ts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ca81b5c-b2fc-4eb5-a270-88ab772ac2d0

📥 Commits

Reviewing files that changed from the base of the PR and between 60fd093 and 58cee43.

📒 Files selected for processing (38)
  • .changeset/publish-types-layout.md
  • .gitignore
  • builds/knockout/package.json
  • builds/knockout/src/index.ts
  • builds/reference/package.json
  • builds/reference/src/index.ts
  • package.json
  • packages/bind/package.json
  • packages/binding.component/package.json
  • packages/binding.core/package.json
  • packages/binding.foreach/package.json
  • packages/binding.if/package.json
  • packages/binding.template/package.json
  • packages/builder/package.json
  • packages/builder/src/Builder.ts
  • packages/computed/package.json
  • packages/filter.punches/package.json
  • packages/lifecycle/package.json
  • packages/observable/package.json
  • packages/provider.attr/package.json
  • packages/provider.bindingstring/package.json
  • packages/provider.component/package.json
  • packages/provider.databind/package.json
  • packages/provider.multi/package.json
  • packages/provider.mustache/package.json
  • packages/provider.native/package.json
  • packages/provider.virtual/package.json
  • packages/provider/package.json
  • packages/utils.component/package.json
  • packages/utils.functionrewrite/package.json
  • packages/utils.jsx/package.json
  • packages/utils.parser/package.json
  • packages/utils/package.json
  • plans/2026-06-04-dts-types-layout.md
  • tools/build-dts.ts
  • tools/types-smoke/consumer.ts
  • tools/types-smoke/tsconfig.json
  • tsconfig.dts.json

Comment thread packages/builder/src/Builder.ts Outdated
Comment thread tools/build-dts.ts
Comment thread tools/types-smoke/tsconfig.json

Copy link
Copy Markdown
Member

On packages/builder/src/Builder.ts: the new create<T extends object[]>(...additionalProperties: T): KnockoutInstance & AdditionalProperties<T> pulls in UnionToIntersection / AdditionalProperties to type a variadic Object.assign merge. The machinery is correct, but it's typing a capability nothing actually uses.

Across the full git history, every builder.create(...) call — both of them, here in builds/knockout and builds/reference — passes a single object. There isn't one multi-arg call anywhere, ever, and the previous signature returned plain KnockoutInstance, so the variadic form never carried any typing value either. The ...additionalProperties spread is vestigial, inherited from the pre-monorepo builder.

Suggest collapsing to a single object argument, which deletes both helper types and is far easier to maintain, while still giving this PR exactly what it's after (a typed default-export surface):

create<T extends object>(additionalProperties: T): KnockoutInstance & T {
  const instance = Object.assign(
    { /* existing getBindingHandler getter/setter */ },
    knockout,
    this.providedProperties,
    additionalProperties
  ) as KnockoutInstance & T
  // ...
}

The two call sites already pass one object, so they're unchanged.

On compatibility: create is technically published via @tko/builder, but it has never been part of the documented external surface — consumers use the bundled ko instance, not Builder directly — so this is effectively an internal API and doesn't warrant a major bump; patch is fine. Since the UnionToIntersection typing is new in this PR, simplest to land it in the single-arg form rather than ship the generic and remove it later.


Generated by Claude Code

Copy link
Copy Markdown
Member

Cosmetic, but valuable while this is open: in builds/reference/src/index.ts, ReferenceBuildExtensions inlines the JSX render return shape:

render(jsx: any): {
  node: ChildNode | DocumentFragment | null
  dispose: () => void
}

The shape is accurate, but it's hand-duplicated. Suggest promoting it to a named type — e.g. JsxRenderResult — exported from @tko/utils.jsx (where JsxObserver and the render logic live), then referencing it both at the render definition and in ReferenceBuildExtensions. Single source of truth, and — now that we're publishing declarations — consumers get a named, importable type for the render result instead of an anonymous object.


Generated by Claude Code

Copy link
Copy Markdown
Member

Cosmetic, but valuable: in tools/build-dts.ts, the workspace-count guard uses a bare literal:

if (workspaces.length !== 27) {
  throw new Error(`Expected 27 publishable workspaces, found ${workspaces.length}`)
}

Suggest a named constant so the intent reads at a glance and the number isn't repeated:

const WORKSPACES_EXPECTED_COUNT = 27
// ...
if (workspaces.length !== WORKSPACES_EXPECTED_COUNT) {
  throw new Error(`Expected ${WORKSPACES_EXPECTED_COUNT} publishable workspaces, found ${workspaces.length}`)
}

When package #26 lands and this guard trips, a named const points the next contributor straight at what needs updating.


Generated by Claude Code

@phillipc

phillipc commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@brianmhunt everything is changed

  1. Named constant for workspace count (tools/build-dts.ts)
    Replaced the bare 27 literal with WORKSPACES_EXPECTED_COUNT so the intent is self-documenting and the number isn't repeated in the error message.

  2. Simplified Builder.create() to single-arg (packages/builder/src/Builder.ts)
    Collapsed create<T extends object[]>(...additionalProperties: T) to create(additionalProperties: T), removing the unused UnionToIntersection and AdditionalProperties helper types. All call sites already passed a single object, so nothing changed at the call sites.

  3. JsxRenderResult type and render() moved to @tko/utils.jsx
    The JsxRenderResult type and render() implementation now live in jsx.ts as the single source of truth. Both are re-exported from @tko/utils.jsx, making JsxRenderResult a named, importable public type for consumers. The reference build now imports and re-exposes render instead of inlining the implementation.

@phillipc

phillipc commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@brianmhunt You know I can't merge without review confirmation? We currently have several branches that have done all feedback notes and are awaiting final approval.

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.

Publish TypeScript declarations (.d.ts) from the 4.x packages

2 participants