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:
- specifying
"libs": ["deno.window", "esnext"]
etc. in the compiler options (in deno.json). - importing the type like this:
/// <reference types="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.dom.d.ts" />
- or this:
// @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?
CodePudding user response:
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/[email protected]/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
- going to be compiled by Deno, and
- is destined to be executed in a browser-like environment
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/[email protected]/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.