Внешние компиляторы закрытия решают проблему, но я не понял, почему?

Я компилирую свой исходный код с помощью компилятора закрытия, и когда я вызываю функцию, которая получила объект события из сети, приложение выдает ошибку в консоли.

Вызывается функция:

/**
 * @param {goog.events.Event} event Socket.io-Wrapper Event.
 */
de.my.app.admin.prototype.onSaved = function(event){ 
  var category = event.data[0].category; //<-- here it throws the error because category get compiled.
  var id       = event.data[0].id;
  var oldid    = event.data[0].oldid;
[...]
}

объект события выглядит так

{ data:{
    0: {
      category: 'someString',
      id:       5,
      oldid:    -5
  } } 
[...someMoreValuesAddedBySocketIO...]
}

это то поведение, которое я ожидал.

теперь я добавляю подобное объявление externs в свой файл externs, но я не менял объявление типа @param в функции, и ошибка исчезает:

var xterns;
/**
 * @typedef {{
 *   category : string,
 *   oldid    : number,
 *   id       : number
 * }}
 */
xterns.NOTUSEDNAME;

/**
 * @type {string}
 */
xterns.NOTUSEDNAME.prototype.category;

/**
 * @type {number}
 */

xterns.NOTUSEDNAME.prototype.oldid;

/**
 * @type {number}
 */
xterns.NOTUSEDNAME.prototype.id;  

Вкратце: у меня есть объявление @param {goog.events.Event} event, а extern для xterns.NOTUSEDNAME решает проблемы с компилятором... Кто-нибудь может объяснить, почему это происходит?


person fastr.de    schedule 17.06.2014    source источник


Ответы (1)


Это распространенное заблуждение. Closure-compiler не будет переименовывать свойство, если любой внешний объект содержит свойство с таким же именем. См. Часто задаваемые вопросы. Если оптимизация на основе типов включена, то это уже не так, и я ожидаю, что ваш код снова сломается.

Чтобы сделать этот тип кода безопасным и скомпилировать без предупреждений, вам нужно:

  1. Ссылайтесь на свойства данных, используя синтаксис event.data[0]['category'] в кавычках. Ваши свойства никогда не будут переименованы компилятором с использованием этого метода (который часто используется данными JSON).

  2. Расширьте тип goog.events.Event с помощью пользовательского объекта, определяющего объект данных как строго типизированный массив.

Пример:

/**
 * @constructor
 * @extends {goog.events.Event}
 */
de.my.app.AdminEvent = function() {};
goog.inherits(de.my.app.AdminEvent, goog.events.Event);

/** @type {Array.<{category:string, id:number, oldid:number}>} */
de.my.app.AdminEvent.prototype.data = []; 

В зависимости от конкретной ситуации интерфейс может быть лучшим вариантом.

person Chad Killingsworth    schedule 17.06.2014