Аннотация плохого типа. Неизвестный тип

Я продолжаю получать предупреждение, упомянутое выше, но не могу понять, почему. Я добавил deps.js, а deps.js содержит ссылку на тип.

Вот код нарушения:

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;
};

В deps.js:

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

Код загружается в html, поэтому он находит класс во время выполнения. Вот как я компилирую код:

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

И он продолжает предупреждать меня:

ПРЕДУПРЕЖДЕНИЕ. Неправильный тип аннотации. Неизвестный тип MyCompany.MyApp.dom

[обновление]

Пытался полностью исключить goog.provide и исключить js=closure/goog/deps.js при компиляции и изменил все на нижний регистр, но продолжает получать одно и то же предупреждение об этом коде:

//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;
};

[обновление]

Дело в том, что когда я добавляю typedef, я получаю предупреждения, что myapp.dom is never defined, но когда я позволяю коду определить тип, я получаю Bad type annotation.

Пытался добавить typedef так:

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

Но на самом деле не понимаю, почему, поскольку goog.provide должен создавать myapp.dom, и компилятор должен это знать.

[обновление]

Я создал следующий myapp.workflow из конструкторов. Теперь компилятор должен распознать тип, и Eclipse сможет помочь с кодом. Не уверен, что это способ сделать это, но я попытаюсь реорганизовать небольшой проект.

Настройка основных типов в 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();

Файл, который вообще не используется в моем коде, но сообщает Eclipse, как выполнять автоматическое завершение:

// 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();
}

Реализация рабочего процесса:

// 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());

Его можно преобразовать в синтаксис myapp.workflow.createOrder=..., заменив myapp.types.WorkFlow.prototype на myapp.workflow, удалив myapp.workflow=new myapp.types.WorkFlow() и удалив goog.require("myapp.types"). Возможно, это можно автоматизировать в процессе сборки/компиляции, если это необходимо.

Я не уверен, что создание одного объекта с помощью функции-конструктора намного дороже, чем просто создание goog.require myapp.workflow и добавление к нему свойств, как я делал раньше (и как это делается в библиотеке закрытия).


comment
почему ни одной из этих функций нет в прототипе? вы используете их как миксины?   -  person lennel    schedule 14.06.2013
comment
Существует только одна mycompany.myapp.dom. Не знает, что свойства одного экземпляра должны быть объявлены в прототипе. Взял пример из array.js, где они используют синтаксис goog.array.something=something. Ни одно из свойств goog.array не добавляется с помощью goog.array.prototype. Я думал, что вы используете прототип для подкласса или когда ожидаете, что будет больше экземпляров (например, функция конструктора).   -  person HMR    schedule 14.06.2013
comment
@lennel Думаю, я вижу причину проблемы. Компилятору не нравится, когда определение типа и реализация — одно и то же. Я попытался передать goog.array в качестве переменной функции, у которой было @param {goog.array} ga goog.array, и получил такое же предупреждение bad type annotation. Пытался сообщить компилятору, что такое this, потому что он продолжает ныть о dangerous use of this in static method В книге, которую я читал, решение заключалось в том, чтобы установить аннотацию @this. Я думаю, что пока просто откажусь от этого, так как это кажется слишком сложным.   -  person HMR    schedule 14.06.2013
comment
Что касается массива, вы должны сделать это {Array.‹type, AnotherType›}, где type и AnotherType — это то, что вы планируете вставить в массив.   -  person lennel    schedule 14.06.2013
comment
Я имею в виду, что синтаксис goog.array является литералом объекта. У него есть такие свойства, как indexof и lastIndexOf. Литералы объектов не имеют типа, поэтому вы не можете сказать, что this контекст его функций равен goog.array, поэтому, когда я буду реализовывать indexof, я должен каждый раз записывать goog.array.someProp вместо this.someProp, иначе компилятор жаловаться на контекст this. Раньше я вводил полное пространство имен, но мне просто было интересно, почему я не могу использовать this в своих функциях, но думаю, что теперь понимаю.   -  person HMR    schedule 15.06.2013


Ответы (1)


Анонимные типы (пространства имен или синглтоны) не имеют определенных типов в Closure-compiler и не могут использоваться в качестве имени типа в аннотации. В качестве имен новых типов можно использовать только конструкторы и интерфейсы. (можно использовать typedef, но на самом деле это просто сокращенные аннотации)

Во многих случаях компилятор правильно выведет типы, и вам не нужно будет аннотировать их. В вашем конкретном случае проблема заключается в том, что вы используете ключевое слово this. Использование ключевого слова this в статическом объекте/пространстве имен опасно и не поддерживается. Компилятор выдаст предупреждение. Хотя вы можете подавить предупреждение с помощью аннотации @this, здесь это неправильное действие, поскольку вы не указываете конкретно ссылку this с помощью .call или .apply.

Решение состоит в том, чтобы использовать полное имя объекта:

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

Для получения полной технической информации см. Это ваше это сообщение.

person Chad Killingsworth    schedule 14.06.2013
comment
Есть ли способ использовать функцию конструктора и по-прежнему использовать goog.provide? Таким образом, я могу определить тип объекта и при этом сообщить компилятору, какой объект предоставляет файл (для calcldeps.py и base.js в нескомпилированном коде). Это было бы неплохо, потому что Eclipse, похоже, любит функции конструктора для помощи в коде. - person HMR; 14.06.2013
comment
Конечно. Лучшим примером является код библиотеки закрытия, такой как docs.closure-library. googlecode.com/git/ – посмотрите что-то вроде goog.fx.dom.PredefinedEffect. - person Chad Killingsworth; 14.06.2013
comment
Я немного борюсь, мой объект dom больше похож на goog.array, и должен быть только один из них, поскольку myapp.dom - это больше пространство имен, чем конструктор. Поскольку мне нужен синтаксис функции конструктора как для компилятора, чтобы выяснить, какой это тип, так и для Eclipse для обработки кода, я не могу использовать синтаксис, используемый в goog.array. Поэтому мне нужно написать его как конструктор, но не нужно инициировать более одного экземпляра. Я немного поиграюсь с этим и посмотрю, что я могу придумать. - person HMR; 14.06.2013
comment
Я обновил свой ответ кодом для myapp.dom, а myapp.workflow попытается реорганизовать один класс в небольшом проекте, который я сделал, чтобы посмотреть, работает ли это. Спасибо за помощь. - person HMR; 14.06.2013