Skip to content

fix(desktop) type declarations for getContext on raw desktop backend - #36182

Open
Giesch wants to merge 5 commits into
denoland:mainfrom
Giesch:giesch/raw-desktop-type-def-fix
Open

fix(desktop) type declarations for getContext on raw desktop backend#36182
Giesch wants to merge 5 commits into
denoland:mainfrom
Giesch:giesch/raw-desktop-type-def-fix

Conversation

@Giesch

@Giesch Giesch commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

This updates the declared types on getContext to match the way they're used in the documentation (returning a GPUCanvasContext for contextId: "webgpu").

Fixes #36214
I used Claude Code while working on this PR

Edited (2026-08-01):

This PR also adds new () construct signatures to the GPUCanvasContext and
ImageBitmapRenderingContext constructor objects, so instanceof type checks and narrows.
Without a construct signature, x instanceof GPUCanvasContext raises TS2359; the alternative
Function & { prototype: X } clears TS2359 but narrows to {} rather than X. This is a
second, independent type-level fix that also benefits OffscreenCanvas users. The construct
signature is documented as not being a supported way to create a context.

@Giesch
Giesch force-pushed the giesch/raw-desktop-type-def-fix branch from cd9632b to a3263fc Compare July 21, 2026 11:56
@Giesch Giesch changed the title fix type declarations for getContext on raw desktop backend fix(desktop) type declarations for getContext on raw desktop backend Jul 21, 2026
@Giesch
Giesch marked this pull request as ready for review July 21, 2026 21:41
Giesch and others added 3 commits July 21, 2026 19:57
…dowSurface.getContext

Mirrors the overload set already declared on OffscreenCanvas.getContext,
so getContext("webgpu") narrows to GPUCanvasContext | null instead of
OffscreenRenderingContext | null. The runtime (ext/canvas/byow.rs)
supports exactly the bitmap and webgpu contexts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…enderingContext

Without a construct signature on the constructor objects,
`x instanceof GPUCanvasContext` fails with TS2359 even though it works
at runtime. Matches the @webgpu/types and lib.dom convention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Giesch
Giesch force-pushed the giesch/raw-desktop-type-def-fix branch from a3263fc to 33dbe98 Compare July 21, 2026 23:58
@bartlomieju

Copy link
Copy Markdown
Member

Checked this against the implementation and the current canary — the change is correct and the test is meaningful:

  • The overloads match the runtime exactly: UnsafeWindowSurface::get_context (ext/canvas/byow.rs:211) dispatches on exactly bitmaprenderer and webgpu, returns Ok(None) for anything else, and also returns None when a different context was already created — so | null on both overloads is right.
  • The new () additions are genuinely required, not incidental. With only { prototype: X }, TS raises TS2359 ("right-hand side of an instanceof must be assignable to Function"), and the plausible alternative Function & { prototype: X } clears TS2359 but narrows to {} instead of X. new () is also what lib.dom.d.ts does for every non-constructible interface, and there's in-repo precedent (new (): GPUError, cli/tsc/dts/lib.deno_webgpu.d.ts:1621).
  • I ran the new main.ts against the unpatched 2.9.3 libs: 6 errors, including the getContext assignability ones. So it does fail before and pass after.

A few things worth tightening:

1. The new () additions contradict the doc comments directly above them. lib.deno_canvas.d.ts:246 says a GPUCanvasContext "is obtained from OffscreenCanvas.getContextrather than constructed directly", same for ImageBitmapRenderingContext. Since the construct signature is needed for instanceof, keep it — but reword those comments (or note that the signature exists only so instanceof narrows), otherwise someone will later "fix" one or the other.

Related, and out of scope for this PR: on canary 2.9.3 new GPUCanvasContext() and new ImageBitmapRenderingContext() currently succeed and hand back an uninitialized object. Per spec these should be illegal constructors (Chrome throws). So the new signature isn't lying today, but it will be once the runtime adds a webidl.illegalConstructor guard — probably deserves its own issue.

2. Mirror the null-returning overload from OffscreenCanvas. lib.deno_canvas.d.ts:310 already documents the ids Deno doesn't implement:

// Spec also defines "2d", "webgl", and "webgl2" context ids; Deno does
// not implement those and getContext returns null for them.
getContext(contextId: "2d" | "webgl" | "webgl2", options?: any): null;

The runtime behaves identically for UnsafeWindowSurface (byow.rs:222, _ => return Ok(None)), and the goal here is to mirror the OffscreenCanvas overloads — so adding that third overload (plus the /** Get a drawing context… */ doc) would make the two declarations actually match.

3. assertType only checks assignability, so it under-constrains. assertType<OffscreenRenderingContext | null>(surface.getContext(contextId)) passes for any narrower return type too. A strict-equality helper would pin the exact types — and, more usefully, lock the overload order, which is the easiest thing to break later:

type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends
  (<T>() => T extends B ? 1 : 2) ? true : false;

Not blocking — the test as written does catch the regression.

4. Nit: "exitCode": 0 in __test__.jsonc is the default and can be dropped.

Scope: the new () change is a second, independent fix (it affects OffscreenCanvas users too), but it's small and directly motivated by the test, so I wouldn't split it. Could you add a sentence about the instanceof fix to the PR description, though, so it isn't a surprise for reviewers and the changelog?

Giesch and others added 2 commits August 1, 2026 10:45
…ndowSurface

Adds the doc comment and the "2d" | "webgl" | "webgl2" overload that
OffscreenCanvas.getContext already declares, so the two declarations read
identically. ext/canvas/byow.rs::get_context returns Ok(None) for any
unrecognized context id, so the null return is accurate.

Also rewords the GPUCanvasContext / ImageBitmapRenderingContext constructor
object docs, which said these are obtained from getContext "rather than
constructed directly" and so contradicted the new construct signature. The
signature is kept because it is what makes instanceof type check and narrow,
and is now documented as not being a supported construction path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replaces the assertType<T>(value) helper, which only checked assignability,
with a strict type-equality assertion. Each call is captured in a const and
queried with typeof so the selected overload's exact return type is pinned;
a wrong return type now fails with TS2344.

Also drops the redundant "exitCode": 0 from __test__.jsonc.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

Missing type signatures for raw webgpu backend

2 participants