Question

I keep getting the warning mentioned above but can't figure out why. I've added deps.js and deps.js contains a reference to the type.

Here is the offending code:

goog.provide("MyCompany.MyApp.dom");


MyCompany.MyApp.dom.getArticleAmountInput_=function(){
    return document.getElementById("articleAmount");
};
/**
 * Gets the article amount input value
 * @type {function(this:MyCompany.MyApp.dom):number} */
MyCompany.MyApp.dom.getArticleAmount=function(){
    var tmp=this.getArticleAmountInput_();
    return (tmp)?tmp.value():undefined;
};

In deps.js:

goog.addDependency('../../MyCompany/MyApp/dom.js', [ 'MyCompany.MyApp.dom'], []);

Code loads in html so it does find the class at runtime. Here is how I compile the code:

java -jar ../../compiler.jar \
--compilation_level=ADVANCED_OPTIMIZATIONS \
--formatting=PRETTY_PRINT \
--warning_level=VERBOSE \
--summary_detail_level=3 \
--js=MyCompany/MyApp/dom.js \
--js=closure/goog/deps.js \
--js_output_file=out.js

And it keeps giving me the warning:

WARNING - Bad type annotation. Unknown type MyCompany.MyApp.dom

[update]

Tried to leave out the goog.provide completely and leave out the js=closure/goog/deps.js when compiling and changed everything to lower case but keep getting the same warning on this code:

//goog.provide("mycompany.myapp.dom");
var mycompany={};
mycompany.myapp={};
mycompany.myapp.dom={};

mycompany.myapp.dom.getArticleAmountInput_=function(){
    return document.getElementById("articleAmount");
};
/**
 * Gets the article amount input value
 * @type {function(this:mycompany.myapp.dom):number} */
mycompany.myapp.dom.getArticleAmount=function(){
    var tmp=this.getArticleAmountInput_();
    return (tmp)?tmp.value():undefined;
};

[update]

The thing is that when I add a typedef I get warnings that myapp.dom is never defined but when I let the code determine what the type is I get Bad type annotation.

Tried to add a typedef like so:

/**
 * @typedef {{getArticleAmount:function(this:myapp.dom):?number}}
 */
myapp.dom;

But don't realy see why as goog.provide should create the myapp.dom and the compiler should know that.

[update]

I have created the following myapp.workflow from constructors. Now the compiler should recognize the type and Eclipse can code assist. Not sure if this is the way to do it but I'll try to re factor a small project.

Setting up the main types in types.js

// source: js/mmyapp/types.js
goog.provide("myapp.types");
/** @constructor */
var gooblediegoog=function(){};
/** @constructor */
gooblediegoog.prototype.WorkFlow=function(){};
/** @constructor */
gooblediegoog.prototype.Dom=function(){};
myapp.types=new gooblediegoog();

A file that isn't used at all in my code but tells Eclipse how to auto complete:

// source: js/myapp/forCodeAssist.js
/** @const {boolean} */
var ALLWAYSFALSE=false;

if(ALLWAYSFALSE){
    /**needed for Eclipse autocomplete
     * @constructor
     */
    var MyApp=function(){};
    MyApp.prototype.types=new gooblediegoog();
    Window.prototype.myapp=new MyApp();
    MyApp.prototype.workflow=new myapp.types.WorkFlow();
    MyApp.prototype.dom=new myapp.types.Dom();
}

An implementation of workflow:

// source: js/myapp/workflow.js
goog.provide("myapp.workflow");
goog.require("myapp.types");
goog.require("myapp.dom");

/** @returns number|undefined */
myapp.types.WorkFlow.prototype.createOrder=function(){
    return myapp.dom.getArticleAmout();
};
myapp.workflow=new myapp.types.WorkFlow();
window['console'].log(myapp.workflow.createOrder());

This can be converted to a myapp.workflow.createOrder=... syntax by replacing myapp.types.WorkFlow.prototype with myapp.workflow, removing myapp.workflow=new myapp.types.WorkFlow() and removing the goog.require("myapp.types"). Maybe this can be automated in the build/compile process if needed.

I am not sure if creating a single object with the help from a constructor function is much more expensive than just having goog.require create myapp.workflow and adding properties to it as I used to do (and as it's done in closure library).

Was it helpful?

Solution

Anonymous types (namespaces or singletons) don't have specific types in Closure-compiler and cannot be used as a type name in an annotation. Only constructors and interfaces can be used as new type names. (typedefs can be used but are really just shorthand annotations)

In many cases the compiler will correctly infer the types and you will not need to annotate it. In your specific case, it looks like the problem is your use of the this keyword. Using the this keyword in a static object / namespace is dangerous and not supported. The compiler will raise a warning. While you can suppress the warning with a @this annotation, that is not the correct action here as you are not specifically specifying the this reference by using .call or .apply.

The solution is to use the full object name:

/**
 * Gets the article amount input value
 */
mycompany.myapp.dom.getArticleAmount=function(){
  var tmp=mycompany.myapp.dom.getArticleAmountInput_();
  return (tmp)?tmp.value():undefined;
};

For the full technical details, reference the This this is your this post.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top