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
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.
@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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With