TypeScript: Avoid require statements in compiled J

2019-07-17 06:58发布

问题:

In my TypeScript code I am using a third-party library called bunyan like so:

private logger: bunyan.Logger = bunyan.createLogger({name: "MyClass"});

Because TypeScript cannot resolve the variable bunyan, I do this to make the TypeScript compiler work:

import * as bunyan from "bunyan";

Unfortunately this causes the following JavaScript output:

var bunyan = require("bunyan");

The require statement will not work in the browser (when not using a requirejs implementation), so I will receive: Uncaught ReferenceError: require is not defined.

Actually I don't need the require statement in my compiled JavaScript because there is a bunyan.min.js (browserified version) which I can use for the browser. But how can I avoid the bunyan import in my TypeScript code without having the TypeScript compiler complaining about an unknown reference?

I am using TypeScript 1.8 and this is my TypeScript compiler configuration:

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitAny": false,
    "removeComments": true,
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "typings/browser",
    "typings/browser.d.ts"
  ]
}

回答1:

You should use declare to declare a module for bunyan with Logger and createLogger.

declare module bunyan {
    export interface Logger {
        info(message: string): any;
        warn(message: string): any;
    }

    export function createLogger(options: any): Logger;
};

class MyClass {
    private logger: bunyan.Logger = bunyan.createLogger({name: "MyClass"});
}

I would recommend using a typings declaration file like the one found here so you get the full benefit of TypeScript :)



回答2:

I found out that there are two things that come into play:

  1. Package reference
  2. Type declaration

Explanation

In my initial code I imported bunyan which helped the TypeScript compiler to find bunyan's declaration. With the assignment of private logger: bunyan.Logger I also forced type safety on my logger variable.

To get rid off the bunyan reference (to also get rid off the compiled var bunyan = require("bunyan"); code) I needed to trick the compiler.

The TS compiler can be cheated by removing the import and telling TypeScript that there is something (any) out in the wild which is named bunyan. This can be done by writing:

declare var bunyan: any;

Because the TS compiler is tricked there is no way for it to guarantee type safety anymore, so the specific type from the logger variable needs to be removed and it's declaration must look like the following statement:

private logger: any = bunyan.createLogger({name: "MyClass"});

This bring us to the following solution:

Before

// Package reference
import * as bunyan from "bunyan"; 

// Type declaration
private logger: bunyan.Logger = bunyan.createLogger({name: "MyClass"});

After

// Package reference
declare var bunyan: any; 

// Type declaration
private logger: any = bunyan.createLogger({name: "MyClass"});

Thanks James Monger for making this clear to me.