You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Not sure whether this has been already mentioned before (I would be surpirsed if it never was)... Wouldn't it be a good idea to name arrow functions, which is what apparently ES6 does?. Think about the benefits of this in the stacktrace. It's quite useful to have a "named" function in there, instead of an anonymous one ;-)
So, this:
constdouble=x=>x*2;
would be transpiled down to:
vardouble=functiondouble(x){returnx*2;};
Just to mention that Babel does it like that ;-)
Thanks.
Reacted by Mike, Dave Taylor, Dan Homola, Kris Kaczor, Jake Ginnivan, Yaroslav, Vladimir Katushenok, JasonS, Bradley Ayers, Aaron Ross and 14 more
This would also be nice to have for arrow functions used as class methods/properties.
Note that we can't safely name class methods -- a reference to handleDocumentClick in the method body must refer to whatever that name means in the enclosing lexical scope, not the function itself.
Regular function expressions have very noncomplaint behavior in current runtimes and should probably just be left alone (specifically, Edge, Chrome, and Node all produce an own property of name on functions, when they shouldn't)
Hi Ryan Cavanaugh (@RyanCavanaugh), answering your question... as far as I know in ES6 if an arrow function is defined on the right-hand-side of an assignment expression, the engine will take the name on the left-hand-side and set the arrow function's ".name" based on that
At this point I'm not sure its entirely necessary to fix this, except in possibly a very small number of cases. If you emit to ES5/ES3, but are running in an ES2015+ host, function names are automatically assigned from their variables using NamedEvaluation (which evolved from variable declaration evaluation in ES2015).
This means that if you have the following typescript:
constf=()=>{};console.log(f.name);
And we transpile it to the following ES5:
varf=function(){};console.log(f.name);
Running that transpiled output will print f. However, if you are running in an ES5/ES3 host environment, all bets are off. .name wasn't standardized until ES2015, so there are no guarantees if you'll get "f", "", or undefined. The number of ES3/ES5 runtime environments is vanishingly small, and many (if not most) libraries and frameworks are dropping support for them.
Broadly emulating NamedEvaluation for ES5 emit would artificially inflate the overall emitted file size, for little benefit. In fact, the only place where I could see it have value is for downleveled exports and class fields, as property assignments do not call NamedEvaluation:
In ES2015+ with native ES modules, the above TS code prints f and x, but when targeting ES5 and commonjs, it prints empty strings.
This could possibly be resolved by leaning on NamedEvaluation for exports:
// es5 (commonjs)varf=function(){}exports.f=f;console.log(exports.f.name);// prints 'f' in an ES2015+ host
Classes are a bit trickier if there is a naming conflict (though we could rename local variables to accommodate):
// tsclassC{x=()=>{};constructor(){varx=1;}};// es5 (commonjs)// option 1, rename localsvarC=(function(){functionC(){varx=function(){};this.x=x;varx_1=1;// renamed local `x` to `x_1`}returnC;})();// option 2, leverage _NamedEvaluation_ using object literalsvarC=(function(){functionC(){this.x={x: function(){}}.x;// NamedEvaluation gives the name `x` to the functionvarx=1;// local not renamed}returnC;})();
One of the reasons to lean on NamedEvaluation is that we can't blindly add a name to a function expression as that can introduce scope conflicts. The name introduced in the function expression is locally scoped to the function expression body. Consider the two following cases:
// case 1exportletfib=(i: number)=>i===1 ? 0 : i===2 ? 1 : fib(i-1)+fib(i-2);constfib2=fib;fib=i=>{console.log("i:",i);returnfib2(i);};console.log("# case 1");console.log("result:",fib(3));// case 2functionf(s: string){console.log(s);}classC{f=(s: string)=>{f("Hello "+s);}}console.log();console.log("# case 2");newC().f("Alice");
If you emit to ESNext using native ES modules, you would get the following results:
# case 1
i: 3
i: 2
i: 1
result: 1
# case 2
Hello Alice
If we were to emit to ES5 and inject names into the functions, the output would change due to scope conflicts:
# case 1
i: 3
result: 1
# case 2
Error: Stack overflow
In case 1, the fib inside of the arrow function ends up pointing at the name fib we might give to the function expression, rather than the outer fib variable.
In case 2, the f we call ends up invoking the function expression we assigned to the field f, rather than the name in the outer scope.
When it was standardized isn't important; it was present in every version of every web browser except IE, and it's web reality that code expects it to work. It's also polyfillable in IE 9+, with https://npmjs.com/function.prototype.name, and there's lots of websites that rely on that working, including airbnb.com (when i last checked, at least).
Every product will have a set of tradeoffs it has to make, and prioritizing the work to do this "by the book" is work with a likely tail of bugs and emit size implications. I can't speak for others who are on this issue, but I tend to agree with Ron that the people who would benefit from this have shrunk a lot as a group. For example:
there's lots of websites that rely on that working, including airbnb.com (when i last checked, at least).
Windows 10 (released late July 2015) actually makes it hard to access IE11. In fact, it will automatically punt you to Edge unless you disable a setting within Edge. But for the sake of it, here's Airbnb running in IE11:
Daniel Rosenwasser (@DanielRosenwasser) that's a totally reasonable assessment; my pushback was against trying to justify not doing the work as a result of when something was standardized.
Regardless of what's done by default, why not offer this as a config option, for those who want to emit correct code?
Activity
adidahiya commentedon Jan 11, 2016
This would also be nice to have for arrow functions used as class methods/properties.
RyanCavanaugh commentedon Jan 11, 2016
Can you clarify this part?
RyanCavanaugh commentedon Jan 11, 2016
Note that we can't safely name class methods -- a reference to
handleDocumentClickin the method body must refer to whatever that name means in the enclosing lexical scope, not the function itself.RyanCavanaugh commentedon Jan 11, 2016
Consulted with Brian Terlson (@bterlson) and we think this is a spec-affecting behavior, specifically the places where the abstract
SetFunctionNameoperation is invoked https://tc39.github.io/ecma262/#sec-setfunctionnameRegular function expressions have very noncomplaint behavior in current runtimes and should probably just be left alone (specifically, Edge, Chrome, and Node all produce an own property of
nameon functions, when they shouldn't)jscriptcoder commentedon Jan 12, 2016
Hi Ryan Cavanaugh (@RyanCavanaugh), answering your question... as far as I know in ES6 if an arrow function is defined on the right-hand-side of an assignment expression, the engine will take the name on the left-hand-side and set the arrow function's ".name" based on that
Thanks
nojvek commentedon May 21, 2016
Hi Ryan Cavanaugh (@RyanCavanaugh), could you explain the SetFunctionName operation? I couldn't fully grasp why it should be an issue.
I tried this in chrome.
Generated typescript:
So it seems under the covers v8 makes nice named anonymous functions.
basarat commentedon May 24, 2016
Tried the following in the chrome dev console. Was surprised 🌹
dsherret commentedon May 25, 2016
Basarat Ali Syed (@basarat) It didn't happen for me in v50.0.2661.102m, but I just upgraded to v51.0.2704.63m and now it's doing that.
33 remaining items
remorses commentedon Mar 27, 2020
Can someone implement this please?
functions with names
functions with names
functions with names
jednano commentedon May 8, 2021
This appears to be fixed now, no?
RyanCavanaugh commentedon May 11, 2021
jedmao no. The relevant test would be
which should produce
under
target: es5rbuckton commentedon Oct 5, 2021
At this point I'm not sure its entirely necessary to fix this, except in possibly a very small number of cases. If you emit to ES5/ES3, but are running in an ES2015+ host, function names are automatically assigned from their variables using NamedEvaluation (which evolved from variable declaration evaluation in ES2015).
This means that if you have the following typescript:
And we transpile it to the following ES5:
Running that transpiled output will print
f. However, if you are running in an ES5/ES3 host environment, all bets are off..namewasn't standardized until ES2015, so there are no guarantees if you'll get"f","", orundefined. The number of ES3/ES5 runtime environments is vanishingly small, and many (if not most) libraries and frameworks are dropping support for them.Broadly emulating NamedEvaluation for ES5 emit would artificially inflate the overall emitted file size, for little benefit. In fact, the only place where I could see it have value is for downleveled exports and class fields, as property assignments do not call NamedEvaluation:
In ES2015+ with native ES modules, the above TS code prints
fandx, but when targeting ES5 and commonjs, it prints empty strings.This could possibly be resolved by leaning on NamedEvaluation for exports:
Classes are a bit trickier if there is a naming conflict (though we could rename local variables to accommodate):
One of the reasons to lean on NamedEvaluation is that we can't blindly add a name to a function expression as that can introduce scope conflicts. The name introduced in the function expression is locally scoped to the function expression body. Consider the two following cases:
If you emit to ESNext using native ES modules, you would get the following results:
If we were to emit to ES5 and inject names into the functions, the output would change due to scope conflicts:
The reason for this would be the resulting emit:
In case 1, the
fibinside of the arrow function ends up pointing at the namefibwe might give to the function expression, rather than the outerfibvariable.In case 2, the
fwe call ends up invoking the function expression we assigned to the fieldf, rather than the name in the outer scope.ljharb commentedon Oct 5, 2021
When it was standardized isn't important; it was present in every version of every web browser except IE, and it's web reality that code expects it to work. It's also polyfillable in IE 9+, with https://npmjs.com/function.prototype.name, and there's lots of websites that rely on that working, including airbnb.com (when i last checked, at least).
DanielRosenwasser commentedon Oct 7, 2021
Every product will have a set of tradeoffs it has to make, and prioritizing the work to do this "by the book" is work with a likely tail of bugs and emit size implications. I can't speak for others who are on this issue, but I tend to agree with Ron that the people who would benefit from this have shrunk a lot as a group. For example:
Windows 10 (released late July 2015) actually makes it hard to access IE11. In fact, it will automatically punt you to Edge unless you disable a setting within Edge. But for the sake of it, here's Airbnb running in IE11:
abnb-ie11.mp4
ljharb commentedon Oct 7, 2021
Daniel Rosenwasser (@DanielRosenwasser) that's a totally reasonable assessment; my pushback was against trying to justify not doing the work as a result of when something was standardized.
Regardless of what's done by default, why not offer this as a config option, for those who want to emit correct code?
sandersn commentedon Dec 3, 2021
This is not practical to fix: the costs far outweigh the benefits.
ljharb commentedon Dec 3, 2021
Nathan Shively-Sanders (@sandersn) even behind an option?