Skip to content

Box URL into checked-dynamic unions beside fetch's Request and Response - #1459

Merged
ctate merged 1 commit into
opt/native-undici-followupsfrom
opt/native-undici-url-unions
Oct 20, 2026
Merged

ctate merged 1 commit into
opt/native-undici-followupsfrom
opt/native-undici-url-unions

Conversation

@cramforce

Copy link
Copy Markdown
Contributor

Box URL into checked-dynamic unions beside fetch's Request and Response

Stacked on #1435.

Summary

Under @types/node, fetch's input is string | URL | Request. A union that holds a checked-dynamic arm, such as fetch's Request handle, collapses to the checked-dynamic representation only when every other arm survives that collapse. URL did not, so the union was refused. The same refusal hit everything typed as typeof globalThis.fetch, including the common pattern of casting a custom fetch through unknown:

const fetchImpl = customFetch as unknown as typeof globalThis.fetch;

URL's checked-dynamic handle already exists and boxes by reference:

  • it keeps object identity;
  • it reads and writes href, pathname, searchParams and the other members through the native accessors;
  • it answers instanceof URL;
  • it checks back out to the typed URL.

So nothing degrades when a URL arm joins the collapse. string | URL, string | URL | Request and similar unions now compile.

The second change is in fetch() itself. An input typed string | URL (a union without a checked-dynamic arm) was narrowed to a string at the call, which threw on the URL arm. Such an input now goes through fetch's existing checked-dynamic input path, which reads the URL's href, as the bare-URL form does.

Programs that don't spell such a union are unaffected. Every other union keeps its existing representation and fences. URLSearchParams stays out of the collapse because instanceof URLSearchParams on a checked-dynamic value is not supported.

Evidence

  • tests/fixtures/node-types/fetch-input-unions.ts, compiled under @types/node through project-config.test.ts, and the same program as corpus 6252-fetch-input-url-unions under scriptc's own declarations. Both are run against Node. They cover:
    • a custom fetch cast to typeof globalThis.fetch;
    • a dispatcher field written through Record<string, unknown>;
    • fetch with string and URL inputs;
    • a string | Request | URL parameter narrowed with instanceof URL, read, written through setters, and read through searchParams.
  • The sanitized lane matches the plain lane for both programs.
  • Zero-cost gate against Lower fetch members typed by @types/node, and run the poll phase once per loop iteration #1435, bench, self and the whole corpus (3,248 programs): every program is identical. Bench geomean +0.08% and self-compile +0.57%, both within tolerance.
  • Lint, format, and test:ts7 --baselines-only (2 new baselines, none changed).

🤖 Generated with Claude Code

fetch's input under @types/node is string | URL | Request. A union with a
checked-dynamic arm collapses to the checked-dynamic representation only
when every sibling survives the collapse; URL did not qualify, so the type
(and anything typed as typeof globalThis.fetch, such as a custom fetch cast
through unknown) did not compile. URL's handle boxes by reference, keeps its
accessors and setters, answers instanceof URL and checks back out to the
typed value, so URL arms now join the collapse. A fetch() input typed
string | URL also converts through the checked-dynamic input path instead
of being narrowed to a string, which threw on the URL arm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
scriptc Ready Ready Preview, v0 Oct 20, 2026 3:55am UTC

@ctate
ctate merged commit 73da783 into opt/native-undici-followups Oct 20, 2026
21 of 23 checks passed
@ctate
ctate deleted the opt/native-undici-url-unions branch October 20, 2026 03:59

This branch was successfully deployed

1 active deployment
Preview — 4e0e7fc1 Deployed Oct 20, 2026 by vercel[bot]
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