Skip to content

[hotwired__turbo] Align types with the v8.0.23 implementation#75208

Open
myabc wants to merge 4 commits into
DefinitelyTyped:masterfrom
myabc:hotwired-turbo/align-types-with-impl
Open

[hotwired__turbo] Align types with the v8.0.23 implementation#75208
myabc wants to merge 4 commits into
DefinitelyTyped:masterfrom
myabc:hotwired-turbo/align-types-with-impl

Conversation

@myabc

@myabc myabc commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🤖 Drafted with agent assistance.

Please fill in this template.

If changing an existing definition:


Result of auditing these declarations against the hotwired/turbo v8.0.23 source and the built dist/turbo.es2017-esm.js export surface.

Fixes #75207: StreamMessage and BrowserAdapter were declared as exported classes, but @hotwired/turbo exports neither at runtime, so value imports compiled and then resolved to undefined (introduced in #74439). Both are now interfaces; tests assert the names are unusable as values. Technically breaking for anyone value-importing them, but that code was already broken at runtime.

Event details

  • turbo:before-render: removed isPreview — not part of the dispatched detail (view.js:72); turbo:render and turbo:before-frame-render: added renderMethod; turbo:reload: typed the { reason, context? } detail.
  • VisitFallback: options is now optional — the turbo:frame-missing fallback can be called as detail.visit(url).

Fetch layer

  • FetchRequest: declared the real constructor (introducing FetchRequestDelegate) so zero-arg new FetchRequest() no longer compiles; added abortController, abortSignal, entries, isSafe, location, defaultHeaders, cancel(), perform(), acceptResponseType().
  • FetchRequest#method and FormSubmission#method use split accessors: the getters return the UPPERCASE verbs the implementation stores (method.toUpperCase()), the setters keep accepting Turbo's lowercase verbs, and FetchRequest#fetchOptions.method is narrowed to the uppercase verbs so the getter is sound. The lowercase union is an internal RequestMethod helper — not exported, matching Turbo, with a test asserting that.
  • FetchResponse: declared the constructor; header() and contentType are string | null (delegating to Headers#get); responseHTML resolves string | undefined; getter-backed members are now readonly.

Previously missing runtime exports

Now declared: fetch (Turbo's X-Turbo-Request-Id-appending wrapper), FetchMethod, FetchEnctype, fetchMethodFromString, fetchEnctypeFromString, isSafe, FrameLoadingStyle, PageRenderer, FrameRenderer, PageSnapshot (minimal statics + getters), and the deprecated setProgressBarDelay / setConfirmMethod.

session.view

Adds TurboSession#view, typed via new PageView and SnapshotCache interfaces (lastRenderedLocation, snapshot, snapshotCache, cacheSnapshot(), …), verified against page_view.js / snapshot_cache.js. Both are type-only, per the same non-runtime-export convention. Motivated by downstream code that must correct view.lastRenderedLocation (it keys the snapshot cache and page-refresh detection) after rewriting the URL through session.history: opf/openproject#23818 (comment).

Cleanups / judgment calls

  • StreamElement attribute getters (action, target, targets, requestId) are string | null — readonly reflections of attributes genuinely absent in common cases (request-id in particular), so unlike the write-side refresh discussion in [hotwired__turbo] Add nullable FrameElement.refresh #75196 the null is observable. Happy to revert if we'd rather idealize here too.
  • visit() / Turbo.visit() accept URL as well as string; Turbo.registerAdapter takes Adapter (was unknown); Turbo.setConfirmMethod matches config.forms.confirm, which may return boolean | Promise<boolean> (the implementation awaits it, so config.forms.confirm = window.confirm type-checks).

Not included (deliberate non-alignments, per #75196): FrameElement.refresh stays "morph" | null; VisitOptions stays the documented { action?, frame? }; FetchResponse.isHTML stays boolean even though the implementation returns a truthy match result (upstream fix candidate); TurboSubmitEndEvent.success stays required even though an aborted submission dispatches without a result.

Audited against hotwired/turbo v8.0.23 source and built dist
export surface.

Event details:
- turbo:before-render: drop isPreview (not in the dispatched
  detail); turbo:render: add renderMethod detail;
  turbo:before-frame-render: add renderMethod; turbo:reload:
  type the reason/context detail
- VisitFallback: make options parameter optional

Fetch layer:
- FetchRequest: declare constructor (with FetchRequestDelegate),
  split method accessors (reads back UPPERCASE, assignments take
  lowercase verbs), add abortController/abortSignal, entries,
  isSafe, location, defaultHeaders, cancel(), perform(),
  acceptResponseType()
- FetchResponse: declare constructor; header() and contentType
  return string | null; responseHTML resolves string | undefined;
  mark getter-backed members readonly
- FormSubmission#method: string (reads back UPPERCASE)

Missing exports now declared: fetch, FetchMethod, FetchEnctype,
fetchMethodFromString, fetchEnctypeFromString, isSafe,
FrameLoadingStyle, PageRenderer, FrameRenderer, PageSnapshot,
setProgressBarDelay, setConfirmMethod (both deprecated)

Cleanups:
- StreamElement attribute getters (action, target, targets,
  requestId) are string | null
- visit() and Turbo.visit() accept URL as well as string
- TurboGlobal.registerAdapter takes Adapter (was unknown);
  Turbo.setConfirmMethod matches config.forms.confirm signature
- config.forms.confirm may return boolean | Promise<boolean>
  (implementation awaits the result)
Copilot AI review requested due to automatic review settings July 4, 2026 16:52
@typescript-automation

typescript-automation Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

@myabc Thank you for submitting this PR!

This is a live comment that I will keep updated.

1 package in this PR

Code Reviews

Because you edited one package and updated the tests (👏), I can help you merge this PR once someone else signs off on it.

You can test the changes of this PR in the Playground.

Status

  • ✅ No merge conflicts
  • ✅ Continuous integration tests have passed
  • 🕐 Most recent commit is approved by type definition owners or DT maintainers

Once every item on this list is checked, I'll ask you for permission to merge and publish the changes.


Diagnostic Information: What the bot saw about this PR
{
  "type": "info",
  "now": "-",
  "pr_number": 75208,
  "author": "myabc",
  "headCommitOid": "4809e8b00626bc150a319c896df8ca73675cf27e",
  "mergeBaseOid": "e2580e07bfb619bbaa80a31c6e9d0e2ec35fea22",
  "lastPushDate": "2026-07-04T16:52:32.000Z",
  "lastActivityDate": "2026-07-04T16:52:32.000Z",
  "hasMergeConflict": false,
  "isFirstContribution": false,
  "tooManyFiles": false,
  "hugeChange": false,
  "tooManyCommits": false,
  "tooManyReviews": false,
  "popularityLevel": "Popular",
  "pkgInfo": [
    {
      "name": "hotwired__turbo",
      "kind": "edit",
      "files": [
        {
          "path": "types/hotwired__turbo/hotwired__turbo-tests.ts",
          "kind": "test"
        },
        {
          "path": "types/hotwired__turbo/index.d.ts",
          "kind": "definition"
        }
      ],
      "owners": [
        "G-Rath",
        "lukeify",
        "myabc"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Popular"
    }
  ],
  "reviews": [],
  "mainBotCommentID": 4883127195,
  "ciResult": "pass"
}

@typescript-automation typescript-automation Bot added Popular package This PR affects a popular package (as counted by NPM download counts). Author is Owner The author of this PR is a listed owner of the package. labels Jul 4, 2026
@typescript-automation typescript-automation Bot moved this to Waiting for Code Reviews in Pull Request Status Board Jul 4, 2026
@typescript-automation

Copy link
Copy Markdown
Contributor

🔔 @G-Rath @lukeify — please review this PR in the next few days. Be sure to explicitly select Approve or Request Changes in the GitHub UI so I know what's going on.

Copilot AI 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.

Pull request overview

Updates the @hotwired/turbo type declarations to better match the Turbo v8.0.23 runtime export surface and behavior (notably events, fetch layer, and additional exported symbols), along with expanded DTS tests to validate the new typings.

Changes:

  • Added typings for previously-missing runtime exports (e.g. fetch, FetchMethod, FetchEnctype, FrameLoadingStyle, PageRenderer, FrameRenderer, PageSnapshot, and deprecated module-level setters).
  • Aligned fetch-layer and event typings with v8.0.23 behavior (e.g. FetchRequest/FetchResponse constructors & members, event detail payloads, VisitFallback options optionality, and visit() accepting URL).
  • Updated tests to exercise the new exports and refined types (including new event/detail expectations and readonly/getter-backed members).

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated no comments.

File Description
types/hotwired__turbo/index.d.ts Aligns exported types and event/fetch APIs with Turbo v8.0.23 and adds typings for additional runtime exports.
types/hotwired__turbo/hotwired__turbo-tests.ts Extends the DTS test suite to cover new exports and updated type expectations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

StreamMessage and BrowserAdapter were declared as exported
classes, but @hotwired/turbo does not export either at runtime
(neither appears in the dist export surface), so value imports
compiled but resolved to undefined. Introduced in DefinitelyTyped#74439.

Convert both to interfaces: StreamMessage keeps its instance
shape (fragment) for renderStreamMessage(); BrowserAdapter now
extends Adapter, keeping progressBar and the members it makes
non-optional. Tests assert both names are no longer usable as
values.

Fixes DefinitelyTyped#75207
myabc added 2 commits July 4, 2026 20:21
Model FetchRequest#method and FormSubmission#method as getter/setter
pairs: reads return uppercase verbs, assignments accept Turbo's
lowercase method names, matching the implementation. Narrow
FetchRequest#fetchOptions.method to the uppercase verbs the request
actually stores.

Keep the new RequestMethod union as an internal helper (with
`export {}`) since Turbo does not export it; tests assert it stays
unexported.
Declare PageView and SnapshotCache interfaces and expose
session.view, verified against hotwired/turbo v8.0.23. Downstream
code needs view.lastRenderedLocation when rewriting the URL through
session.history, so the snapshot cache and page-refresh detection
stay keyed to the rendered location.

Both are type-only declarations (Turbo does not export the classes
at runtime), following the existing BrowserAdapter/StreamMessage
convention; tests assert they are not constructible.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author is Owner The author of this PR is a listed owner of the package. Popular package This PR affects a popular package (as counted by NPM download counts).

Projects

Status: Waiting for Code Reviews

Development

Successfully merging this pull request may close these issues.

[hotwired__turbo] StreamMessage and BrowserAdapter are declared as value exports but do not exist at runtime

2 participants