In Flow, what does Missing an annotation on implicit `this` parameter of function. [missing-this-annot] mean?

306 Views Asked by At

I have a Javascript file that looks like this:

// @flow
/**
 * My database module.
 *
 * Interact with the database.
 */
'use strict';

module.exports = {

  /** Mockable wrapper around mongoose. */
  mongoose: function() /*:: : Object */ {
    // $FlowExpectedError
    return require('mongoose');
  },

  /** Mockable wrapper around env. */
  env: function() /*:: : Object */ {
    // $FlowExpectedError
    return require('./env.js');
  },

  /** Initialize the connection to Mongoose. */
  init: function(
    callbackOK /*:: : () => number */,
    callbackInitError /*:: : (x: string) => null */,
    callbackError /*:: : (x: string) => null */) {

    try {
      // See https://mongoosejs.com/docs/connections.html.
      this.mongoose().connect(this.uri(), {}).then(
        () => callbackOK(),
        err => callbackInitError(err),
      );
      this.mongoose().connection.on('error',
        err => callbackError(err),
      );
    }
    catch (err) {
      callbackInitError(err);
    }
  },

  /** Get the connection URI for the Mongoose database. */
  uri: function() /*:: : string */ {
    const user = String(this.env().required('MONGO_USER'));
    const pass = String(this.env().required('MONGO_PASS'));
    const host = String(this.env().required('MONGO_HOST'));
    const port = String(this.env().required('MONGO_PORT'));
    const db = String(this.env().required('MONGO_DB'));

    return 'mongodb://' + user + ':' + pass + '@' + host + ':' + port + '/' + db + '?authSource=admin';
  },
};

When I check it with Flow, it gives me this error:

Missing an annotation on implicit `this` parameter of function. [missing-this-annot]

                       v
   24|   init: function(
   25|     callbackOK /*:: : () => number */,
   26|     callbackInitError /*:: : (x: string) => null */,
   27|     callbackError /*:: : (x: string) => null */) {
           -------------------------------------------^

How would I modify this code to fix this error?

1

There are 1 best solutions below

0
Ricola On

Reason

According to https://medium.com/flow-type/sound-typing-for-this-in-flow-d62db2af969e, you have to explicitly type the This parameter.

Let's just say that Flow was not producing any error here. Then Flow could not prevent you to do this:

const foo = module.exports.uri;
foo();

But this will throw at runtime as global this doesn't have an env function.

Solution 1

You could define a type for your module:

type MyModule = {
  mongoose:  () => Object,
  env: () => Object,
  init: 
    (callbackOK : () => number,
    callbackInitError: (x: string) => null,
    callbackError: (x: string) => null) => void,

  uri: () => string
}

Then in the functions where you call this, you would have to add a special this annotation:

  uri: function(this: MyModule) {

This shouldn't change the function signature as long as you have have a recent version of Babel (at least 7.13.0 according to the article above).

Flow try link

Solution 2

You might not like defining the types into two different places. Then why not get rid of this altogether?

Declare each function at the top level, e.g.

function uri() /*:: : string */ {
    const user = String(env().required('MONGO_USER'));
    ...
}

And then export them:

module.exports = {
  mongoose, 
  env,
  init,
  uri,
}

Flow try link