I'm using Deno to compile some TypeScript and then serve it as part of a web page, so that it is run on the browser side. I'm trying to use a canvas element on the client side, and for that I need types like CanvasRenderingContext2D
or CanvasGradient
, which are defined in lib.dom.d.ts, but they are not available: Deno compilation gives errors like TS2304 [ERROR]: Cannot find name 'CanvasRenderingContext2D'.
. (On the other hand, type Path2D
(defined in the same file) does not cause problems.)
Note: I know the types will exist in runtime when the code runs in the browser, but I want Deno to know about them in compile time.
I've tried including the .d.ts file somehow. Things I tried:
"libs": ["deno.window", "esnext"]
etc. in the compiler options (in deno.json)./// <reference types="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.dom.d.ts" />
// @deno-types="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.dom.d.ts"
Some of these attempts didn't work at all, and some weren't even parsed apparently. Looks like I don't understand how Deno loads the type definitions, e.g. where does it load the Path2D
type declarations from. How to fix this?
You need to configure Deno to use only DOM and ES types when type-checking your program. You can do this using the supported TypeScript compiler options in a Deno config file:
./deno.json
:
{
"compilerOptions": {
"lib": [
"esnext",
"dom",
"dom.iterable"
]
}
}
This instructs the compiler that the program won't be running in Deno, but in a browser-like environment with those ambient global types.
Here's an example source file:
./main.ts
import {assertExists} from 'https://deno.land/std@0.126.0/testing/asserts.ts';
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
assertExists(ctx);
When you import from other TypeScript modules into a module like this that's
then you'll have to bundle the result, because browsers can't process TypeScript source modules as imports:
deno bundle --config deno.json main.ts main.js
The resulting JavaScript looks like this:
// deno-fmt-ignore-file
// deno-lint-ignore-file
// This code was bundled using `deno bundle` and it's not recommended to edit it manually
const { Deno } = globalThis;
typeof Deno?.noColor === "boolean" ? Deno.noColor : true;
new RegExp([
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
].join("|"), "g");
var DiffType;
(function(DiffType1) {
DiffType1["removed"] = "removed";
DiffType1["common"] = "common";
DiffType1["added"] = "added";
})(DiffType || (DiffType = {}));
class AssertionError extends Error {
name = "AssertionError";
constructor(message){
super(message);
}
}
function assertExists(actual, msg) {
if (actual === undefined || actual === null) {
if (!msg) {
msg = `actual: "${actual}" expected to not be null or undefined`;
}
throw new AssertionError(msg);
}
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
assertExists(ctx);
It's safe to use the module at https://deno.land/std@0.126.0/testing/asserts.ts
in the compilation of your program because it does runtime feature-detection of the Deno namespace before trying to use any of its APIs. Any modules which don't do that will result in a runtime error.