Skip to content

fix(types): rewrite type definitions#142

Open
VastBlast wants to merge 5 commits intocloudflare:mainfrom
VastBlast:rewrite-types
Open

fix(types): rewrite type definitions#142
VastBlast wants to merge 5 commits intocloudflare:mainfrom
VastBlast:rewrite-types

Conversation

@VastBlast
Copy link
Contributor

@VastBlast VastBlast commented Feb 20, 2026

This PR rewrites type definitions to fix a ton of issues. I believe this closes all the open & confirmed type issues/bugs reported. Based on my testing, I did not find any new issues, but please let me know if anything slipped.

My motivation for this stemmed from the current type definitions being incredibly hard to work with in my current project due to the bugs. The library is very neat in terms of actual functionality and performance (which I love) but the types are hard to work with.

I will admit, AI assisted with a lot of this (gpt-5.3-codex:Xhigh), but I did ultimately rewrite parts myself. However, my methodology was not blindly using AI: I first wrote several type tests and created a type-testing suite to run against many different base/edge cases. I then tested it against the current types, before using AI to both rewrite the types. After many hours, feedback loops, and handwritten rewrites, I finally landed on this.

I decided against adding those tests to this PR since I do not know if that is something wanted or structured in a specific way. Let me know if you'd like them added and I can push them here.

While working on this, I noticed a comment left by @kentonv:

Thanks but getting the types right is a pretty complicated issue and I think it's best left to the team that understands the model precisely.

So I understand if this is being worked on internally and you'd rather not accept a PR, but I do think its worth looking into these types and potentially using what you can from it.

Here are the list of changes/fixes:

  • any return values no longer leak through as any.
    • parse(): any now gives api.parse(): Promise<unknown> (not Promise<any>).

    Fixes "Type instantiation is excessively deep and possibly infinite" when calling a method on an untyped session #53

  • Inline callback params are contextually inferred from RpcStub<(...args) => ...> signatures.
    • with run(cb: RpcStub<(n: number) => void>), stub.run(n => n.toFixed()) infers n as number (not any).

    Fixes Callback parameter type not inferred from RpcStub (implicitly any) #134

  • map() callback results now reject native promises (including nested ones) and inputs are intentionally non-thenable placeholders.
    • api.listUsers().map(u => Promise.resolve(u.getName())) is a type error.
    • api.listNames().map(name => name.then(...)) is now a type error.

    Fixes Returning a bare Promise from map errors at runtime without a TypeScript error #54

  • unknown return values are now handled consistently.
    • getUnknown(): unknown gives api.getUnknown(): Promise<unknown> instead of degrading to unusable/never shapes.

    Fixes unknown inference is broken #118

  • unknown object fields are now accepted in RPC-compatible types.
    • Record<string, unknown> is treated as valid RpcCompatible.

    Fixes unknown inference is broken #118

  • map() callback placeholder values can now be forwarded into params directly.
    • api.listIds().map(id => api.getUser(id)) type-checks even though id is a map placeholder, not a plain number.
  • Callable placeholders in map() keep their call signatures.
    • if each item is (n: number) => string, then formatter(1) is allowed and formatter("x") is rejected.
  • Array vs tuple providers are now typed separately for better index behavior.
    • for Promise<readonly [number, User]>, stub[0] is typed from the tuple slot instead of generic array fallback.
  • Stubify/Unstubify now filter to string/number keys in mapped objects, so symbol-keyed properties are excluded from RPC object mapping.
  • UnstubifyAll now uses readonly unknown[], so for example methods expecting readonly [string, number] keep that in stub call args.

@changeset-bot
Copy link

changeset-bot bot commented Feb 20, 2026

⚠️ No Changeset found

Latest commit: f95cd50

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@kentonv
Copy link
Member

kentonv commented Feb 25, 2026

Thanks, these look like sorely needed improvements to the types!

I will need to find some time to review this carefully -- it may take a week or two as I'm pretty swamped at the moment. But I wanted to let you know I've seen this and am eager to integrate it as bizarre type errors are a sore spot I'm seeing a lot of right now.

@vicary
Copy link

vicary commented Feb 27, 2026

My honest suggestion is to add type-only tests with recursive nesting, and a N-depth type inference.

We are manually restricting the type depth in our codebase by policy. So it's quite useful for us to know the new depth limit, if this gets merged.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 7, 2026

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/capnweb@142

commit: e26b277

@kentonv
Copy link
Member

kentonv commented Mar 7, 2026

Hi @VastBlast!

Thanks so much for this PR. These fixes look great and I think are more thorough than what I would have likely come up with.

A couple requests:

  • I'd love to have the type tests. Could you add them to the PR?
  • It looks like you re-ordered RpcCompatible, StubBase, and Stub relative to TypedArray and BaseType, which makes the diff harder to read. Could you move them back to their old ordering to make the diff clear?

Thanks!

@kentonv
Copy link
Member

kentonv commented Mar 7, 2026

And sorry again for the slow review, it's been an excessively busy few weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants