Closure库中有几个地方接口有一对addImplementation/isImplementedBy
函数来对接口进行运行时类型检查(类似于this answer)。我并不完全是这个解决方案的粉丝,我有一些非常简单的东西。有没有办法在启用ADVANCED_OPTIMIZATIONS的情况下进行鸭子打字?假设我有一个界面,以及对具有该界面的儿童采取特殊操作的组件,例如:
/** @interface */
MyInterface = function() {};
MyInterface.prototype.doSomething = function() {};
/**
* @constructor
* @extends {goog.ui.Component}
*/
MyComponent = function() {
...
};
/** @inheritDoc */
MyComponent.prototype.addChild = function(child, opt_render) {
goog.base(this, 'addChild', child, opt_render);
if (child.doSomething) {
child.doSomething();
}
};

ADVANCED_OPTIMIZATIONS会不断重命名" doSomething"属性与实现?如果没有,会添加一个类型联合确保它会吗? e.g。
/**
* @param {goog.ui.Component|MyInterface} child
*/
MyComponent.prototype.addChild = function( child, opt_render) {
if (child.doSomething) {
child.doSomething();
}
};

答案 0 :(得分:2)
这是添加@record
的内容。您需要使用最新版本的编译器才能使用它(至少在2016年有所作为)。
只需将@interface
替换为@record
即可获得所需的行为。编译器将一致地重命名。
答案 1 :(得分:1)
我把Chad的答案作为决议留下了,但是一旦我完成编辑工作就重新审视了这个问题,并且为了后人的缘故,我发布了一个更详细的答案来解决鸭子打字的一般情况。
您可以使用ADVANCED优化执行动态向下转换,如下所示:
var maybeRecordType = /** @type {MyRecordType} */ (someObject);
if ( maybeRecordType.propertyInQuestion ) {
maybeRecordType.propertyInQuestion();
}
如果传递的两种可能类型之间的属性名称发生冲突,那么显然会以这种方式丢失编译时检查,但这总是存在使用duck typing的风险。