Closed azz closed 6 months ago
We need to do this for ES6 compat
Open question -- what should happen when the function name is a quoted name that is an invalid identifier?
class Thing {
'foo bar'() { }
}
var x = new Thing();
console.log(x['foo bar'].name);
ES6 prints foo bar
, Babel prints fooBar
(wat), TypeScript prints undefined
.
set it explicitly?...
Object.defineProperty(Thing.prototype["foo bar"], "name", { configurable: true, writable: false, enumerable: false, value:"foo bar" });
You'd basically have to do the same thing we do for computed properties in object literals and split off at the first property with a string name whose name is not a valid identifier name.
Another time using a named function wouldn't work is when the method accesses an outer variable with the same name:
var func;
class ClassName {
func() { return func; }
}
Edit: a named function could also be incorrectly fetched by eval
:
var func;
class ClassName {
func(s) { return eval(s); }
}
new ClassName().func('func');
@jeffreymorlan has a point.
var func = "aa";
class ClassName {
func() { return func; }
}
new ClassName().func();
returns "aa" in Chrome console
var func = "aa";
var ClassName = (function () {
function ClassName() {
}
ClassName.prototype.func = function func() { return func; };
return ClassName;
})();
new ClassName().func();
returns function func() { return func; }
in Chrome console.
@jeffreymorlan The outer element with the conflicting name could be aliased under a different variable name.
I ran into this issue and I see that it was pushed back from several versions. Is there a desire for this feature?
@LPGhatguy even if aliasing were possible, that doesn't solve the eval
case.
To avoid the issues pointed out by @jeffreymorlan, would the emitter have to emit Object.defineProperty(...)
for all methods? If so:
This complexity explains why the issue has been pushed back. That being said, I would like to see it solved. As @RyanCavanaugh pointed out, it is needed for ES2015 compatibility.
I suppose a __methodNames
helper could be emitted at the top of the file:
// ES5 emit:
var __methodNames = (this && this.__methodNames) || function (proto, keys) {
for (var i = keys.length - 1; i >= 0; i--) {
Object.defineProperty(proto[keys[i]], 'name', {
value: keys[i], configurable: true, writable: false, enumerable: false
});
}
};
Emitting for methods, similar to how __decorate
works:
ClassName.prototype.foo = function () {
// ...
};
ClassName.prototype['bar baz'] = function () {
// ...
};
__methodNames(ClassName.prototype, ['foo', 'bar baz']);
Is this planned for version 2.3 now? It really ruined the day for my test framework and will be loved when it comes.
Any progress on it?
Hello, are there any updates on this issue? According to the latest activity above (on 8/31/2017), it was supposed to be added to TypeScript 2.6 but it isn't there in it. Also, if it's not too late, I would like to suggest that the name should include the class name as well (ClassName$functionName, for example). In large projects where the same function is used by several classes (for example when overriding a function from a base class), the function name alone isn't sufficient to uniquely identify the actual function. It would be even better if there was a way to control the prefix.
Bump
This seems to be working for me just fine (at least for TypeScript v2.9.2).
Be sure that your tsconfig.json
file (or however you're setting your compilerOptions) has compilerOptions.target
set to "es2015" | "es6"
or later.
Using ts-node
with target >= "es2015":
> class Foo {
... bar() {}
... }
> let foo = new Foo();
undefined
> foo.bar.name
'bar'
> foo.constructor.name
'Foo'
I threw that last bit in there for @Manish3177 . No need to include the class name in the method name as it can be retrieved from the constructor object on the class instance.
Be sure that your tsconfig.json file (or however you're setting your compilerOptions) has compilerOptions.target set to "es2015" | "es6" or later.
That just means we're not downleveling the method declaration. The issue is for the downleveling targets.
+1. The main reason why I need name for methods:
async convert() {
const log = ObjectToLinksConverter.classLog.extend(this.convert.name);
}
I have described the problem on this stackoverflow question and written the solution
Solution
I have described the problem on this stackoverflow question and written the solution
@jannesiera @Manish3177 @Jack-Works @ob3c @pinyin @sonicd300 @elado @jfahrenkrug @Fallenstedt @joseph-of-wheel @a-tarasyuk @MattiasBuelens
This doesn't seem like an important scenario for modern JS development - folks can either target ES6 which is supported basically everywhere, or use an alternate transpiler with stricter adherence semantics if this is important for their scenario.
This issue has been asked as a question on StackOverflow.
I have a TypeScript class, and I'm doing some metaprogramming where I need to be able to access
instance.func.name
, however TypeScript omits the function name in the compiled JS.TypeScript:
Compiled JavaScript:
Desired JavaScript:
Not sure if this is a bug or by design, but the source of the result is emitter.ts.
A proposed solution on StackOverflow was: