Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
This repository was archived by the owner on May 22, 2025. It is now read-only.

Use interfaces instead of namespaces in externs #1223

Open
@theseanl

Description

@theseanl

Currently, tsickle creates one namespace per file in externs, declares exported members as properties of such a namespace, and pass it around to express import * as ns syntax. This seems to be causing closure compiler to be overly conservative on property mangling, according to google/closure-compiler#2132.

This have had positive effects, namely, it has hided many problems with generated externs -- sometimes the generated externs skips over some properties over a namespace, but apparently the above issue make closure compiler to safely back off on such non-declared properties. But now this is being worked on, IMO tsickle could switch to interface-per-file format as described in the above issue. It would have another benefit of expressing export * from '...' syntax cleanly as multiple @extends.

I am not sure whether the below is a good closure compiler annotation, but it seems to be compiling well.

/** @externs */

/**********************************************************************/

/** @interface */
var intf1 = function() {};

/**
 * @constructor
 * @struct
 */
intf1.prototype.X = function() {};

/** @type {string} */
intf1.prototype.X.prototype.foo;

/** @type{!intf1} */
var myNs1;

/**********************************************************************/

/** @interface */
var intf2 = function() {};

/**
 * @record
 * @struct
 */
intf2.prototype.Y = function() {};

/** @type {string} */
intf2.prototype.Y.prototype.bar;

/** @type {!intf2} */
var myNs2;

/**********************************************************************/

/**
 * @interface
 * @extends {intf1}
 * @extends {intf2}
 */
var intf = function() {};

/** @type {!intf} */
var myNs
/**
 * @fileoverview 
 * @suppress {uselessCode}
 */

myNs.X;

(new myNs.X()).foo;
(new myNs.X()).bar; // [JSC_INEXISTENT_PROPERTY] Property bar never defined on intf1.prototype.X

/**
 * @param {intf1.prototype.X} x
 * @param {intf2.prototype.Y} y
 */
function g(x, y) {
    x.foo = y.bar;
    x = y; // [JSC_TYPE_MISMATCH] assignment found : ... required : ...
}

myNs.Z // [JSC_INEXISTENT_PROPERTY] Property Z never defined on intf

(Moved from #1220 (comment))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions