在 Closure 中检测接口和鸭子类型
Detecting interfaces and duck typing in Closure
Closure 库中有几个地方的接口有一对 addImplementation/isImplementedBy
函数来对接口进行运行时类型检查(类似于 )。我不完全喜欢这个解决方案,因为我有一些非常简单的东西。有没有办法在启用 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" 属性?如果不是,添加类型联合会确保它会吗?例如
/**
* @param {goog.ui.Component|MyInterface} child
*/
MyComponent.prototype.addChild = function( child, opt_render) {
if (child.doSomething) {
child.doSomething();
}
};
这就是添加 @record
的目的。您需要使用最新版本的编译器才能使用它(至少是 2016 年的版本)。
只需将 @interface
替换为 @record
,您应该会得到您想要的行为。编译器会一致地重命名。
我将查德的回答作为解决方案,但在我开始编译后重新审视了这个问题,为了后代,我发布了一个更详细的鸭子打字一般情况的答案。
您可以使用 ADVANCED 优化执行动态向下转换,如下所示:
var maybeRecordType = /** @type {MyRecordType} */ (someObject);
if ( maybeRecordType.propertyInQuestion ) {
maybeRecordType.propertyInQuestion();
}
如果传递的两种可能类型之间的 属性 名称存在冲突,那么您显然会以这种方式失去编译时检查,但这始终是鸭子类型的风险。
Closure 库中有几个地方的接口有一对 addImplementation/isImplementedBy
函数来对接口进行运行时类型检查(类似于
/** @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" 属性?如果不是,添加类型联合会确保它会吗?例如
/**
* @param {goog.ui.Component|MyInterface} child
*/
MyComponent.prototype.addChild = function( child, opt_render) {
if (child.doSomething) {
child.doSomething();
}
};
这就是添加 @record
的目的。您需要使用最新版本的编译器才能使用它(至少是 2016 年的版本)。
只需将 @interface
替换为 @record
,您应该会得到您想要的行为。编译器会一致地重命名。
我将查德的回答作为解决方案,但在我开始编译后重新审视了这个问题,为了后代,我发布了一个更详细的鸭子打字一般情况的答案。
您可以使用 ADVANCED 优化执行动态向下转换,如下所示:
var maybeRecordType = /** @type {MyRecordType} */ (someObject);
if ( maybeRecordType.propertyInQuestion ) {
maybeRecordType.propertyInQuestion();
}
如果传递的两种可能类型之间的 属性 名称存在冲突,那么您显然会以这种方式失去编译时检查,但这始终是鸭子类型的风险。