6

While extending Cheerio library, I implemented the following static function (other extension functions work fine):

$.nodeType = function (elem: CheerioElement): number {
    switch (elem.type) {
        case "comment":
            return Node.COMMENT_NODE; // <--- it fails here
        case "tag":
            return Node.ELEMENT_NODE; // <--- it fails here
        case "text":
            return Node.TEXT_NODE;    // <--- it fails here
        default:
            return -1;
    }
};

The following error appears during runtime (compilation with tsc -b succeed):

ReferenceError: Node is not defined

Node interface is part of the DOM API. Thus, I realized the need of explicitly include the DOM API under compilerOptions section of tsconfig.json.

However, I still get that runtime error.

Minimal relevant part of tsconfig.json:

{
    "compilerOptions": {
        "baseUrl": ".",
        "incremental": true,
        "lib": [
            "esnext",
            "dom"
        ],
        "module": "commonjs",
        "noImplicitAny": true,
        "outDir": "./lib/",
        "sourceMap": true,
        "target": "esnext",
        "watch": true
    },
    "include": [
        "./src/**/*.ts",
    ]
}

I thought of explicitly import Node lib in the specific .ts file which contains the function, but I didn't find any "include-able" standard DOM lib.

Dorad
  • 3,413
  • 2
  • 44
  • 71
  • You cannot use interfaces as values. They're types. Types don't exist at runtime. – Estus Flask Apr 14 '19 at 16:19
  • Thanks @estus, i understood. It's the answer so post it as one... – Dorad Apr 14 '19 at 17:16
  • I'm not sure that it's a good answer since it doesn't explain how it should be fixed. I cannot say how this should be fixed without seeing the context but it's likely can be fixed with JSDOM, as the answer suggests. – Estus Flask Apr 14 '19 at 19:39

2 Answers2

1

Including a typescript lib doesn't polyfill the feature in an environment where it is not available.

While including "dom" type definitions will make the types available (at the compile time), but it doesn't actually make the Node API (typically provided by the browser runtime) available at runtime.

If you really need this functionality at runtime, you will need to also include an implementation of DOM for node.js such as jsdom which provides this API.

lorefnon
  • 12,875
  • 6
  • 61
  • 93
1

lorefnon explained the problem; here's a slightly hacky way to fix it:

  1. Install jsdom

    npm install jsdom
    
  2. Add this to the top of your file:

    const { JSDOM } = require('jsdom'); // or import { JSDOM } from 'jsdom';
    const Node = new JSDOM('').window.Node;
    
bmaupin
  • 14,427
  • 5
  • 89
  • 94