Search code examples
typescriptexpressdeno

How do I use Express as a dependency, in deps.ts


Following the example to use Express with Deno:

// @deno-types="npm:@types/[email protected]"
import express from "npm:[email protected]";

const app = express();

app.get("/", (req, res) => {
  res.send("Welcome to the Dinosaur API!");
});

app.listen(8000);

I want to put the dependencies in "deps.ts"

But two issues arise:

A) How do I "export" the express namespace in the deps.ts? This does not work:

enter image description here

B) How do I "export" the type declarations? I assume they should go in a dev_deps.ts file? Do I only put the // @deno-types="npm:@types/[email protected]" line in that file?


Solution

  • When importing express in module code (ESM), it is the default export. So, to export it, the syntax is:

    // @deno-types="npm:@types/[email protected]"
    export { default as express } from "npm:[email protected]";
    //       ^1         ^2
    // 1. Identifier of original export
    // 2. The re-exported alias (name)
    

    To re-export types from the associated @types/express package, you can simply export the types from that package:

    ./deps.ts:

    // @deno-types="npm:@types/[email protected]"
    export { default as express } from "npm:[email protected]";
    
    export type {
      Application,
      RouterOptions,
      // etc.
    } from "npm:@types/[email protected]";
    
    

    Then, you can use those exports in another module like this:

    ./main.ts:

    import { type Application, express } from "./deps.ts";
    
    const app: Application = express();
    
    console.log(typeof app); // "function"
    
    

    This is the terminal output:

    % deno check main.ts
    Check file:///Users/deno/so-76719582/main.ts
    
    % deno run --allow-env --allow-read=. main.ts
    function
    
    

    However, in the case of express, the types are all available on the express identifier — it serves as both a functional namespace for values, and a (TypeScript) namespace for types — so you can skip exporting the types separately:

    ./deps.ts:

    // @deno-types="npm:@types/[email protected]"
    export { default as express } from "npm:[email protected]";
    
    

    ./main.ts:

    import { express } from "./deps.ts";
    
    const app: express.Application = express();
    
    console.log(typeof app); // "function"
    
    

    The output remains the same:

    % deno check main.ts
    Check file:///Users/deno/so-76719582/main.ts
    
    % deno run --allow-env --allow-read=. main.ts
    function
    
    

    The version of Deno being used for the code in this answer:

    % deno --version
    deno 1.35.1 (release, aarch64-apple-darwin)
    v8 11.6.189.7
    typescript 5.1.6
    
    

    If you're interested in learning more about the above ideas, see the TS handbook section Namespaces and Modules, and here's an example of the same identifier being used for a value and for a type.