Search code examples
typescriptlighthouse

Correctly use export = and export default in Typescript to create types for lighthouse


I'm trying to create a .d.ts for this lighthouse file and I strugle to understand how to deal with the default export

https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-core/index.js#L28

module.exports = function(url, flags = {}, configJSON) {
  const startTime = Date.now();
  return Promise.resolve().then(_ => {
    // set logging preferences, assume quiet
    flags.logLevel = flags.logLevel || 'error';
    log.setLevel(flags.logLevel);

    // Use ConfigParser to generate a valid config file
    const config = new Config(configJSON, flags.configPath);

    const connection = new ChromeProtocol(flags.port, flags.hostname);

    // kick off a lighthouse run
    return Runner.run(connection, {url, flags, config})
      .then(lighthouseResults => {
        // Annotate with time to run lighthouse.
        const endTime = Date.now();
        lighthouseResults.timing = lighthouseResults.timing || {};
        lighthouseResults.timing.total = endTime - startTime;

        return lighthouseResults;
      });
  });
};

module.exports.getAuditList = Runner.getAuditList;
module.exports.traceCategories = require('./gather/driver').traceCategories;
module.exports.Audit = require('./audits/audit');
module.exports.Gatherer = require('./gather/gatherers/gatherer');

At this stage, I have a lighthouse.d.ts file in my project with:

declare module "lighthouse" {

  export interface flags {
    port: number;
    disableCpuThrottling: boolean;
    disableDeviceEmulation: boolean;
    disableNetworkThrottling: boolean;
  }

  export default function lighthouse(url: string, flags: flags, perfConfig: any): any
}

It seems to be typed properly. if I import using import * as lighthouse from "lighthouse";, I can do lighthouse.default and lighthouse.flags where I need.

But if I run my code, I get TypeError: lighthouse.default is not a function. Am I forced to use export =? If I don't have choice, how to use export = but export the function, the flags type, and getAuditList, traceCategories, Audit, Gatherer?


Solution

  • This is the way that a commonjs module exports something as default ...

    module.exports.default = ...;
    

    ... and there's no sign of it in the code sample. The module exports just one function and assign some properties to it. Try using this as a starting point for a .d.ts:

    declare module "lighthouse" { // the module name must be in quotes
    
        const lighthouse: { // it must be a "const".
    
            //here starts the signature "(...): any " that describes the object as callable
            (url: string, 
             flags: { 
                         port?: number;                       // all of these flags keys must be "?"
                         disableCpuThrottling?: boolean;      // because the parameter initializer
                         disableDeviceEmulation?: boolean;    // is an empty {}
                         disableNetworkThrottling?: boolean;  //
             } = {}, 
             perfConfig: any): any; 
    
    
            //  and here are all the properties that the library has attached to the function.
            getAuditList: ...;    // 
            traceCategories: ...; //  give them the correct type for a better compiler support
            Audit: ...;           // 
            Gatherer: ...;        //
        }
    
        export = lighthouse; // <-finally
    }
    

    And this is how it must be used in a .ts file

    import * as lighthouse from "lighthouse";
    
    lighthouse(...);                //<- invoke it directly
    ...lighthouse.traceCategories...; //<- get access to one of it's properties
    

    Using "export =" will not wrap the function inside an object so the transpiled .js file will be like:

    var lighthouse = require("lighthouse");
    lighthouse(...); // this is the desired result and not _whateverName.lighthouse(...);