How to use types from lib.dom.d.ts when compiling with Deno?
Asked Answered
C

2

4

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?

Custodian answered 23/2, 2022 at 17:39 Comment(0)
E
5

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.

Erlindaerline answered 23/2, 2022 at 22:1 Comment(4)
There's an open issue related to the lack of tree-shaking performed by Deno.emit (which is currently the same algorithm used by deno bundle in the CLI).Erlindaerline
Yes, I figured out the part with bundling. I'm actually using Deno.emit unstable API to run the bundler. Looks like passing lib: ["esnext", "dom"] there helps. IDE still shows the types as missing but the Deno.emit compilation succeeds. Thanks a lot.Custodian
@Custodian FWIW: it's been a long time since I've used this, but you might find some of it useful: github.com/jsejcksn/deno-userscript-bundler/tree/v0.2.3/bundlerErlindaerline
This is explained in the docs here: deno.land/manual/typescript/…Alfieri
L
1

You can use this if you want to include the dom types within a file.

/// <reference lib="dom" />

You can use this if you want to define it for the project deno.json

{
  "compilerOptions": {
    "lib": [
      "dom"
    ]
  }
}
Lounging answered 27/5, 2023 at 3:12 Comment(1)
Was able to simply add the reference without adding dom to lib. Thanks!Lemke

© 2022 - 2024 — McMap. All rights reserved.