We have some code that does a monkey-patch of a library function (maybe a bad design, but there may be other better examples of a similar pattern). The structure of the code looks about like this:
// This is code in a library
class Printer {
value = 'b';
print() {
console.log(`value is ${this.value}`);
}
protected getUpperCaseValue() {
return this.value.toUpperCase();
}
}
// This is code that monkey-patches it
(function patchPrinter() {
// Notice the use of an intersection type to expose the protected method
function newPrint(this: Printer&{getUpperCaseValue(): string}) {
// Call the protected `getUpperCaseValue` via the intersection type
console.log(`capitalized is ${this.getUpperCaseValue()}`);
}
Printer.prototype.print = newPrint;
})();
The resulting JavaScript code generated by Tsickle looks like this:
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
goog.module('google3.cloud.signals.stackdriver.monitoring.frontend.modules.api_clients.example');
var module = module || { id: 'cloud/signals/stackdriver/monitoring/frontend/modules/api_clients/example.closure.js' };
module = module;
exports = {};
class Printer {
constructor() {
this.value = 'b';
}
/**
* @return {void}
*/
print() {
console.log(`value is ${this.value}`);
}
/**
* @protected
* @return {string}
*/
getUpperCaseValue() {
return this.value.toUpperCase();
}
}
if (false) {
/** @type {string} */
Printer.prototype.value;
}
(function patchPrinter() {
/**
* @this {?}
* @return {void}
*/
function newPrint() {
console.log(`capitalized is ${this.getUpperCaseValue()}`);
}
Printer.prototype.print = newPrint;
})();
Notice the @this {?}
type. The problem in our code was that this triggers the Closure conformance unknown this check.
Ideally I would want this to create a Closure type that matched the TypeScript intersection type. This seems to be related to the outstanding tsickle issue Feature Request: Support intersections of object types