Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test if object is implementation of interface in Google Closure class framework

How can I test if an JavaScript object is an implementation of an interface using the Google Closure inheritance mechanism?


I could not find any hint of my.Animal in the objects created via new my.Dog() and object instanceof my.Animal didn't work. The only information about the interface are compiler errors when forgetting to implement methods in the child class.

/**
 * @interface
 */
my.Animal = function() {};

/**
 * Does something.
 * @return {string}
 */
my.Animal.prototype.doSomething;

/**
 * @constructor
 * @implements {my.Animal}
 */
my.Dog = function() {};

/** @inheritDoc */
my.Dog.prototype.doSomething() = function {
    return "something";
}

var dog = new my.Dog();
console.log(dog instanceof my.Animal); // returns false

One way I found is to approximately test for the property of the interfaces, though that's bad in so many aspects:

console.log(!!dog.doSomething); // returns true
like image 629
Sebastian Barth Avatar asked Oct 20 '22 18:10

Sebastian Barth


2 Answers

You can't directly.

In the Closure-compiler type system, @extends is used for inheritance and correlates to instanceof tests. Interface implementations denoted by @implements are strictly a compile time check. They are a promise that your object contains methods and properties that match the definitions of the interface.

As such, to test for them at runtime in a comprehensive fashion, you would need to check for the existance and type of each property of the interface.

like image 30
Chad Killingsworth Avatar answered Oct 24 '22 07:10

Chad Killingsworth


@interface is purely a type checker construct. In uncompiled code there is nothing that can inspect the comments for @interface/@implements to add any wiring for runtime checks. The goal for Closure is that the code will run the same before and after compilation (assuming that you observe the restriction for the optimization mode you are using). The typical pattern when a runtime check is desired is to tag class that implements the interface you are interested in:

my.Dog.prototype.implements_my_Animal = true;

then

if (foo.implements_my_Animal) ...

This is a bit annoying so you don't see it where it isn't needed. There are various ways to wrap this but, if you use ADVANCED mode, most result in the implementing class (my.Dog in your example) escaping and not being removable if unused.

like image 109
John Avatar answered Oct 24 '22 08:10

John