Skip to content

fix(rest): Fix type errors when using concrete body types with subclassed RestEndpoint#3845

Merged
ntucker merged 1 commit intomasterfrom
fix/pathargs-any-subclass
Apr 1, 2026
Merged

fix(rest): Fix type errors when using concrete body types with subclassed RestEndpoint#3845
ntucker merged 1 commit intomasterfrom
fix/pathargs-any-subclass

Conversation

@ntucker
Copy link
Copy Markdown
Collaborator

@ntucker ntucker commented Apr 1, 2026

Motivation

Subclassing RestEndpoint with O extends RestGenerics = any — the standard pattern for adding auth headers, custom serialization, etc. — produced type errors when specifying concrete body types. PathArgs<any> evaluated to KeysToArgs<string> ({[x:string]: string|number}), a restrictive index-signature that rejected concrete body objects.

This was introduced in #3782 (TypeScript 6 upgrade), where [O['searchParams']] extends [undefined] tuple wrapping was added to prevent undefined→any widening in non-strict mode. That fix was correct for union types, but regressed the O = any case.

Solution

Add unknown extends S ? any as the first branch in PathArgs and PathArgsAndSearch. This detects any specifically (unknown extends any is true, unknown extends string is false) and short-circuits to any, allowing normal type inference for subclassed endpoints.

Uses unknown extends S instead of the standard 0 extends 1 & T IsAny pattern because the latter doesn't resolve correctly inside constrained generic parameters (S extends string) in TypeScript 6.

Changes:

  • pathTypes.ts: Add unknown extends S ? any guard to PathArgs and PathArgsAndSearch
  • pathTypes.test.ts: Assert PathArgs<any> and PathArgsAndSearch<any> equal any
  • types.test.ts: Add inheritance tests with AuthdEndpoint<O extends RestGenerics = any> covering constructor, extend, and path changes with concrete body types

Open questions

N/A

Made with Cursor


Note

Low Risk
Type-level changes to PathArgs/PathArgsAndSearch affect TypeScript inference for generic path values; runtime behavior is unchanged and coverage is added via TS tests.

Overview
Fixes a TypeScript regression where subclassing RestEndpoint with O extends RestGenerics = any caused overly-restrictive path arg inference, which then rejected concrete body types.

Updates PathArgs and PathArgsAndSearch to short-circuit to any when the path type is any, and adds TypeScript tests covering PathArgs<any> plus common subclassing/extend() scenarios. Generated playground .d.ts types are updated accordingly, and a patch changeset documents the fix.

Written by Cursor Bugbot for commit 3f62c46. This will update automatically on new commits. Configure here.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 1, 2026

🦋 Changeset detected

Latest commit: 3f62c46

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@data-client/rest Patch
example-benchmark-react Patch
test-bundlesize Patch
coinbase-lite Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 1, 2026

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

Project Deployment Actions Updated (UTC)
docs-site Ready Ready Preview, Comment Apr 1, 2026 1:31pm

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Size Change: 0 B

Total Size: 80.9 kB

ℹ️ View Unchanged
Filename Size
examples/test-bundlesize/dist/App.js 3.44 kB
examples/test-bundlesize/dist/polyfill.js 307 B
examples/test-bundlesize/dist/rdcClient.js 10.4 kB
examples/test-bundlesize/dist/rdcEndpoint.js 6.35 kB
examples/test-bundlesize/dist/react.js 59.7 kB
examples/test-bundlesize/dist/webpack-runtime.js 726 B

compressed-size-action

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.08%. Comparing base (ea9bb2d) to head (0e44fd9).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #3845   +/-   ##
=======================================
  Coverage   98.08%   98.08%           
=======================================
  Files         152      152           
  Lines        2871     2871           
  Branches      563      563           
=======================================
  Hits         2816     2816           
  Misses         11       11           
  Partials       44       44           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

When subclassing RestEndpoint with `O extends RestGenerics = any`,
concrete body types were rejected because PathArgs<any> produced a
restrictive index-signature type.

Add `unknown extends S ? any` guard to PathArgs and PathArgsAndSearch
so the `any` case passes through without constraint. Uses `unknown
extends S` instead of the standard `0 extends 1 & T` IsAny pattern
because the latter doesn't resolve correctly inside constrained
generic parameters in TypeScript 6.

Made-with: Cursor
@ntucker ntucker force-pushed the fix/pathargs-any-subclass branch from 0e44fd9 to 3f62c46 Compare April 1, 2026 13:29
@ntucker ntucker merged commit 14095fe into master Apr 1, 2026
5 of 7 checks passed
@ntucker ntucker deleted the fix/pathargs-any-subclass branch April 1, 2026 13:29
@github-actions github-actions bot mentioned this pull request Apr 1, 2026
ntucker added a commit that referenced this pull request Apr 1, 2026
Add `unknown extends O ? any :` before the searchParams conditional in
RestEndpoint<O> and RestEndpointConstructorOptions<O>. When subclassing
with `O extends RestGenerics = any`, this catches O=any before it reaches
PathArgs, preventing the restrictive index-signature type.

Includes detailed comment explaining the partial inference limitation
where TypeScript may widen path literals to `string` due to complex
conditional constructor parameter types.

Follows up on #3845 which fixed PathArgs<any> but missed the higher-level
propagation through RestEndpointTypes.

Made-with: Cursor
ntucker added a commit that referenced this pull request Apr 1, 2026
Add `unknown extends O ? any :` before the searchParams conditional in
RestEndpoint<O> and RestEndpointConstructorOptions<O>. When subclassing
with `O extends RestGenerics = any`, this catches O=any before it reaches
PathArgs, preventing the restrictive index-signature type.

Includes detailed comment explaining the partial inference limitation
where TypeScript may widen path literals to `string` due to complex
conditional constructor parameter types.

Follows up on #3845 which fixed PathArgs<any> but missed the higher-level
propagation through RestEndpointTypes.

Made-with: Cursor
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.

1 participant