Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define global types when code is wrapped in functions

This question is about using Google Closure Compiler's type annotations properly.

We have a convention that every javascript file is wrapped in a function. Example file:

Square.js:

(function() {
    'use strict';

    /**
     * @constructor
     */
    function Square() {};

    Square.prototype.draw = function() {
    };

}());

If we define a type (such as a constructor) inside this function, closure compiler is not aware of it in other files. For example, in another file:

foo.js:

(function() {
    'use strict';

    /** @param {Square} square */
    function drawSquare(square) {
        square.draw();
    }

}());

Compiling it with -W VERBOSE gives an error that the type Square is not defined:

foo.js:4: WARNING - Bad type annotation. Unknown type Square
        /** @type {Square} square */
                   ^

0 error(s), 1 warning(s), 83.3% typed

We've created externs for all our classes, in separate files, to work around this. Creating externs is a bad solution because now we have to maintain two files for every class.

  1. Is it possible to share the types if files are wrapped by a file-level function?
  2. What's the recommended way of working with closure in general for sharing types between files? Does using closure library provide/require help in any way?
like image 449
sinelaw Avatar asked Oct 31 '22 23:10

sinelaw


1 Answers

I suppose you can manage to have it work by exporting the symbol with the name you want to use outside the restricted scope of the enclosing function. Something like this:

(function() {
    goog.provide('Square');
    //'use strict';

    /**
     * @constructor
     */
    function Square() {};

    Square.prototype.draw = function() {
      return "\\o/";
    };
    goog.exportSymbol('Square', Square);
}());

However, I think your problem is here:

We have a convention that every javascript file is wrapped in a function.

Closure has a different convention, which is to define namespaces.

To answer your second question, the recommended closure way is:

goog.provide('my.Square');
/**
 * @constructor
 */
my.Square = function() {
};

my.Square.prototype.draw = function() {
  // TODO
};

and:

goog.provide('my.App');

goog.require('my.Square');


/**
 * @param {my.Square} square The square to draw
 */
my.App.prototype.drawSquare = function(square) {
  square.draw();
};
like image 198
rds Avatar answered Nov 09 '22 09:11

rds