Björn Morén
Björn Morén

Reputation: 773

Google Closure compiler: class as function argument

I can't figure out how to send class references as function arguments, so that Google Closure compiler will compile it right in advanced mode. In the below example I send a class reference to the Test1.doSomething function, which invokes a static function on the class. I've set the @param to Function, because I guess it still is a function, although I use ES6 style classes. Is there some other keyword I should use?

The below code works fine uncompiled, and also works fine if I go old school and change "class Test2" into "function Test2()". I've also tried to change the @param into function(), function(new:Test2), function(this:Test2), typeof Test2, etc, with no success.

class Test1
{
    /**
     * @param {!Function} typeRef   
     */    
    doSomething(typeRef)
    {
        typeRef.doSomething();
    }
}

class Test2
{
}

Test2.doSomething = function()
{
    alert(1);
}

var t1 = new Test1();
window["t1"] = t1;
t1.doSomething(Test2);

I compile as follows:

--debug --formatting=PRETTY_PRINT --language_in ECMASCRIPT6_STRICT --language_out ECMASCRIPT6_STRICT --compilation_level ADVANCED_OPTIMIZATIONS --js Test.js --js_output_file Script.js

The result with "class Test2"

'use strict';
class $Test1$$ {
}
window.t1 = new $Test1$$;

The result with "function Test2()"

'use strict';
class $Test1$$ {
  $doSomething$($typeRef$$) {
    $typeRef$$.$doSomething$();
  }
}
function $Test2$$() {
}
$Test2$$.$doSomething$ = function $$Test2$$$$doSomething$$() {
  alert(1);
};
var $t1$$ = new $Test1$$;
window.t1 = $t1$$;
$t1$$.$doSomething$($Test2$$);

EDIT ON 29 JAN: Added a more complete example of what I'm trying to do:

class Car
{
    constructor()
    {
        this.make = "Ford";
        console.log("Car created.");
    }
}
Car.create = function(registry)
{
    let obj = new Car();
    registry.add(obj);
    return obj;
}

class Motorcycle
{
    constructor()
    {
        this.make = "BMW";
        console.log("Motorcycle created.");
    }
}
Motorcycle.create = function(registry)
{
    let obj = new Motorcycle();
    registry.add(obj);
    return obj;
}

class Registry
{
    constructor()
    {
        this.vehicles = [];
    }
    add(vehicle)
    {
        this.vehicles.push(vehicle);
    }
    makeVehicle(typeRef)
    {
        typeRef.create(this);
    }

}

function init()
{
    var registry = new Registry();

    registry.makeVehicle(Car);
    registry.makeVehicle(Motorcycle);
    registry.makeVehicle(Motorcycle);
    registry.makeVehicle(Car);
    registry.makeVehicle(Car);
}

Upvotes: 1

Views: 472

Answers (1)

Graham P Heath
Graham P Heath

Reputation: 7389

To pass in a class, you can use the {typeof namespace} type:

@param {typeof Test2} TypeRef   

As in your code:

class Test1
{
    /**
     * @param {typeof Test2} TypeRef   
     */    
    doSomething(TypeRef)
    {
        (new TypeRef()).doSomething();
    }
}

class Test2
{
  doSomething ()
  {
    alert(1);
  }
}

var t1 = new Test1();
window["t1"] = t1;
t1.doSomething(Test2);

Demo (don't forget to hit Compile)

When using @param (without typeof) you would pass an instance of that type*. This is far more common than passing a class itself

*: Sorry if this is not relevant but I noticed a couple of issues in the original code and wanted to show you how to fix them, even if not relevant;

To produce an instance-typed version, I had to change 3 things;

1) The Test2.doSomething assignment should be assigning to Test2.prototype;

Test2.prototype.doSomething = function()
{
    alert(1);
}

Or using the ES6 Class format:

Test2 
{
    doSomething() 
    {
         alert(1);
    }
}

2) And to resolve a warning Test1.doSomething's @param annotation had to become Type2, as Function does not declare a Function.doSomething method.

/**
 * @param {!Type2} typeRef   
 */

3) The final line passes the class itself, not an instance of the class, so you should use the new operator to send in an instance of that class.

t1.doSomething(new Test2());

Cheers.

Upvotes: 1

Related Questions