闭包编译器externs解决了一个问题,但我不明白为什么?

时间:2014-06-17 15:42:47

标签: javascript google-closure-compiler google-closure google-closure-library

我使用闭包编译器编译我的源代码,当我调用一个从网络获取事件对象的函数时,应用程序在控制台中抛出错误。

调用的函数是:

/**
 * @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...]
}

这是我预期的行为。

现在我将这样的外部声明添加到我的外部文件,但我没有改变函数@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声明,xterns.NOTUSEDNAME的extern解决了编译器问题...... 任何人都可以解释为什么会这样吗?

1 个答案:

答案 0 :(得分:3)

这是一种常见的误解。如果任何 extern对象包含同名属性,Closure-compiler将不会重命名属性。请参阅FAQ。如果启用了基于类型的优化,那么这不再是真的,我希望你的代码再次中断。

要使此代码类型安全并在没有警告的情况下进行编译,您需要:

  1. 使用引用的语法event.data[0]['category']引用数据属性。编译器永远不会使用此方法重命名您的属性(通常由JSON数据使用)。

  2. 使用自定义对象扩展goog.events.Event类型,该对象将数据对象定义为强类型数组。

  3. 示例:

    /**
     * @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 = []; 
    

    根据您的具体情况,界面可能是更好的选择。

相关问题