Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Identifier has already been declared when using a class and namespace named identically AND a class decorator #27895

Open
k-j0 opened this issue Jan 31, 2025 · 1 comment

Comments

@k-j0
Copy link

k-j0 commented Jan 31, 2025

Version: Deno 2.1.7

The following code produces a SyntaxError: Identifier '_Bar' has already been declared (needs the experimentalDecorators TS compiler option turned on):

function foo (): ClassDecorator {
    return (_target) => {};
}

@foo()
class Bar {
}

namespace Bar {
    const baz = 1;
}

The issue only occurs when a decorator is applied to a class and a (non-empty) namespace shares the class' name. The following is the tsc-transpiled JS, which does not exhibit the issue:

var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
    if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
    return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
function foo() {
    return function (_target) { };
}
var Bar = function () {
    var _classDecorators = [foo()];
    var _classDescriptor;
    var _classExtraInitializers = [];
    var _classThis;
    var Bar = _classThis = /** @class */ (function () {
        function Bar_1() {
        }
        return Bar_1;
    }());
    __setFunctionName(_classThis, "Bar");
    (function () {
        var _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
        __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
        Bar = _classThis = _classDescriptor.value;
        if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        __runInitializers(_classThis, _classExtraInitializers);
    })();
    return Bar = _classThis;
}();
(function (Bar) {
    var baz = 1;
})(Bar || (Bar = {}));
@marvinhagemeister
Copy link
Contributor

For reference: This is the compiled output from Deno

// ...snip bunch of decorator polyfill code

var _dec, _initClass;
function foo() {
  return (_target)=>{};
}
let _Bar;
_dec = foo();
class Bar {
  static{
    ({ c: [_Bar, _initClass] } = _apply_decs_2203_r(this, [], [
      _dec
    ]));
  }
  static{
    _initClass();
  }
}
let _Bar;
(function(_Bar) {
  const baz = 1;
})(_Bar || (_Bar = {}));

There _Bar is declared twice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants