Skip to content

Instantly share code, notes, and snippets.

@draffensperger
Last active December 7, 2018 15:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save draffensperger/2b0d57abf1fd391be5d0e65ef24a3979 to your computer and use it in GitHub Desktop.
Save draffensperger/2b0d57abf1fd391be5d0e65ef24a3979 to your computer and use it in GitHub Desktop.
Tsickle intersection type unknown this

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment