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

Enum output differences between es5 and es2015 (Declaration Merging Support) #961

Open
@dallastjames

Description

@dallastjames

So, I'll prefix this with the fact that this is my first foray into typescript compiler code, so if I'm just missing obvious things, I apologize in advance. 👍

I posted a bug in the ng-packagr library back in March related to an issue during compiling with declaration merging. Since it hasn't received any solutions, I figured I'd try my hand at tracking down the cause of the error. The tl;dr of that issue is that enum declaration merging with namespaces throws a Identifier {name} has already been declared error. This is the initial code based on the typescript declaration merging documentation

enum AdapterType {
    MapValue = '[Adapter Type] map value',
    MapClass = '[Adapter Type] map class'
}
namespace AdapterType {
    /**
     * Contains an ordered array of the valid AdapterType members
     */
    export const members: AdapterType[] = [AdapterType.MapClass, AdapterType.MapValue];
}

export { AdapterType };

And this is the output when compiling to es2015.

// es2015, es6, etc.
/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/** @enum {string} */
const AdapterType = {
    MapValue: '[Adapter Type] map value',
    MapClass: '[Adapter Type] map class',
};
var AdapterType;
(function (AdapterType) {
    AdapterType.members = [AdapterType.MapClass, AdapterType.MapValue];
})(AdapterType || (AdapterType = {}));
export { AdapterType };

You'll notice that the enum is declared initially with the const keyword, which means that the code that follows is invalid since you can't redeclare a const. The es5 version of this code that gets output uses the var keyword initially, which allows the build to continue successfully.

// es5
/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/** @enum {string} */
var AdapterType = {
    MapValue: '[Adapter Type] map value',
    MapClass: '[Adapter Type] map class',
};
var AdapterType;
(function (AdapterType) {
    AdapterType.members = [AdapterType.MapClass, AdapterType.MapValue];
})(AdapterType || (AdapterType = {}));
export { AdapterType };

As far as I know, the output of enums as const is correct starting in es2015 since that's when those keywords were introduced, however, by doing this, it prevents compilation when using declaration merging. When running this enum file through tsc and ngc, in both cases the generated output used the var keyword regardless of target.

So, my question is, does tsickle generate enums as a const for the closure compiler for a specific reason? (again, forgive my ignorance in the compiler world if this is an obvious thing). If not, I'd love to open a discussion of what could be done to better support typescript declaration merging.

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