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

export const myname = () => {} functions have no name (according to React Devtools) #14127

Closed
aaronbeall opened this issue Feb 16, 2017 · 7 comments
Labels
Duplicate An existing issue was already created
Milestone

Comments

@aaronbeall
Copy link

aaronbeall commented Feb 16, 2017

TypeScript Version: 2.1.5

This issue was originally reported to React Dev Tools and Dan Abramov referred me to log an issue here.

Code

const ArrowFunction = () => { }; // OK
function NamedFunction() { } // OK

export const ExportedArrowFunction = () => { }; // Problem: shows <Unknown> in react-dev-tools
export function ExportedNamedFunction() { } // OK

const ExportedArrowFunctionOnObject = () => { }; // OK
export { ExportedArrowFunctionOnObject } // OK

Expected behavior:
Using Chrome's React Dev Tools and using each function above as a React functional stateless component, I expected to see each function name in the tools, ex <ArrowFunction> and <ExportedArrowFunction>.

Actual behavior:
As mentioned in code comments in the above example, all function forms show their name in tools as expected except ExportedArrowFunction, which shows as <Unknown>. (And unfortunately, this has become the most common form in my code as of late!) This is apparently because it does not have a function.name. It seems that the export throws off the browser's ability to derive a name from the function. Looking at the emitted ES5 (using AMD modules? I'm actually using CommonJS modules but it looks very similar) I'm guessing that the assignment exports.ExportedArrowFunction = function () { } is what throws browsers off, in that it doesn't pick up ExportedArrowFunction as the name.

Solution?
In the original issue thread it was advised by Dan Abramov that a .name should be emitted by the compiler (if I understood his comment). However it looks like TS does not emit a .name for any function. When I used to write ES5 (many years ago -- thank-you TS! :) ) I would always give my functions names, even when I assigned them to things, like exports.ExportedArrowFunction = function ExportedArrowFunction() {} so that the name would appear in call-stacks. Maybe this could work here? Is there another way we could have exported const functions get a proper name?

@DanielRosenwasser
Copy link
Member

This is actually part of the ES spec, but we just haven't implemented it.

We could fix this, but one has to be careful in the following case:

export var foo = 10;

var x = {
  foo: () => foo
}

A naive transformation would result in

export var foo = 10;

var x = {
  foo: function foo() { return foo }
}

which is wrong.

I'll note that as a workaround, you could just use function declarations instead. I've never understood why a person would want to use the

const x = () => {
    // ...
}

pattern given that function declarations often take fewer characters. 😄

@DanielRosenwasser DanielRosenwasser added ES6 Relates to the ES6 Spec Bug A bug in TypeScript labels Feb 17, 2017
@aaronbeall
Copy link
Author

aaronbeall commented Feb 17, 2017

Hm, interesting.

That example looks like it would actually work fine in ES5 emit but I see your point.

Looking at how Babel compiles these examples I see they always emit named functions, and they add a _ to avoid name scope clashes.

I've never understood why a person would want to use the const x = () => { } pattern given that function declarations often take fewer characters

Well I used to feel that way, but it also lets you omit the { } brackets and return which makes for clean functional expressions, and then you want consistently so you start using it everywhere. :) And for whatever reasons this is the form that has become standard convention with React stateless functional components...

@mhegazy
Copy link
Contributor

mhegazy commented Feb 17, 2017

Duplicate of #6433

@mhegazy mhegazy added Duplicate An existing issue was already created and removed Bug A bug in TypeScript Duplicate An existing issue was already created labels Feb 17, 2017
@Hotell
Copy link

Hotell commented Mar 24, 2017

And for whatever reasons this is the form that has become standard convention with React stateless functional components...

I don't think there is any "standard" it's just how some of people are using it.

I for instance prefer function because the power of hoisting. Anyway React Stateless component is just a function not a special REACT pattern.

How we are dealing with this behaviour is explicitly exporting stuff which is also good pattern which makes every js file/module consistent -> imports on the top, exports at the bottom

import * as React from 'react';
import {SFC} from 'react';
import {SomeCmp} from './components';

type HelloProps = {who:string}
const Hello: SFC<HelloProps> = ({who,children}) => (
  <div>
    <h4>Who are you? -> {who}</h4>
    <p>{children}</p>
  </div>
);

export {
 Hello,
 HelloProps // this is needed to mage `declaration: true` work
}

@aaronbeall
Copy link
Author

aaronbeall commented Mar 24, 2017

I don't think there is any "standard" it's just how some of people are using it.

Absolutely, it's not a real "standard" just a (very) common pattern, especially for React SFCs but also JS functions in general. There's various good reasons for it (new and this restrictions, etc), and some tradeoffs, I personally don't have a strong preference either way; that's all besides the point, the point is that this common pattern and a particular intersection of common patterns (exported function expression) causes unexpected/undesirable behavior only in TS (ie not Babel). Not really TS's fault, either, but it's confusing, and could be fixed by TS (whether its worthwhile is still a legitimate question). Personally it took me (and others) awhile to even figure out what was going on here.

How we are dealing with this behaviour is explicitly exporting stuff which is also good pattern which makes every js file/module consistent -> imports on the top, exports at the bottom

Yeah that's the workaround I posted in the original thread, but again, its not as common a pattern and can cause some confusion (2 github "confused" emojis, the ultimate proof! /joking). It's sort of a hidden dependency for devs.

@Hotell
Copy link

Hotell commented Mar 24, 2017

yup yup fair points, absolutely agree.

cheers man 🍻

there is also solution to use TS just for type checking and Babel for transpilation, but I personally try to avoid "double compilation"

@bradleyayers
Copy link

bradleyayers commented May 25, 2018

@DanielRosenwasser the const foo = () => {…} pattern is nice because it allows you to specify the type of foo, which isn't possible with function foo() {…}, e.g.

const Foo: React.SFC = props => <p>{props.children}</p>

I just got bitten by the export const foo = () => {…} CJS emit being exports.foo = () => {…} which Chrome does not infer the name foo for. It would be very useful if the emit preserved the names at runtime.

I use this for storybooks and tests where I need to name the thing I'm demonstrating:

// test
describe(Foo.name, () => {
  it("does something");
});

// storybook
storiesOf(Foo.name, module).add("default", () => <Foo />);

I like this pattern because it leverages the power of "rename", so that tests and storybooks are renamed properly when I perform a rename on the subject.

@RyanCavanaugh RyanCavanaugh added Duplicate An existing issue was already created and removed ES6 Relates to the ES6 Spec labels Mar 7, 2019
tash-2s added a commit to tash-2s/onchain-game-2019_archive that referenced this issue Oct 5, 2023
ref.
`export const myname = () => {}` functions have no name (according to React Devtools) · Issue #14127 · Microsoft/TypeScript microsoft/TypeScript#14127

---

Original commit (web-client): bcbef901cb709c047fb12935473b163e1483efce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

6 participants