-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Extremely poor ES6 module import syntax for default exports #2370
Comments
This happened because the original module system produced for ES6 favored multiple exports. This did not match what is in current use (single-item exports in CommonJS). They tried to fix that and the fix resulted with confusing syntax which tries to make default import first class while still preserving multiple exports. You should definitely open a thread on esdiscuss by going here but I wouldn't keep my hopes up. The key way to understand the ES6 module system is to always think "multiple exports". Thats why the default export is imported using The fact that the default import syntax hides this is both helpful (not repeating |
I completely disagree with most of the points you make here, but let me go through them bit by bit. Remember, the module syntax in ES6 (which is what this is, just added to TypeScript) was designed to please both people coming from CommonJS and people comming from AMD, and had to be statically verifiable as well as a whole bunch of other requirements. The syntax has been iterated quite a few times already, and the way you imported whole modules ( Now, first off, let's look at the default import import X from './foo'; What this does, is basically replace the simple let X = require('./foo'); True, the functionality is actually different, but the usage should be the same once we start writing modules with this syntax, because instead of setting I actually am much more confused by your proposed syntax import 'M' as X; This is something akin to what the old "import *" syntax used to look like, and that's basically what I interpret it as. If Now, the beauty about the last syntax is that the authors realized that 90% of the time when we write modules we end up doing either this: let foo = require('./foo'),
bar = foo.bar
baz = foo.baz; or let foo = require('./foo');
// later
doSomeStuff(foo.bar); We normally don't need a handle for the module's export itself. Normally we're only interested in some (or all) of the exports. Thus a syntax was added to address that. And the beauty of it is that it's almost just an appliance of destructing. Basically, you can turn this: import {bar} from './foo'; into this: import * as foo from './foo';
let {bar} = foo; |
@Alxandr, I appreciate the points you've made about compatibility and trying to capture the "spirit" of legacy and different module systems (though many of them had very little use in practice such older ES6 drafts or less popular ones such as RequireJS, or wasn't heavily used on the web like CommonJS), but my approach to evaluating syntax is mainly based on general readability and parallelisms with natural language semantics, similar to the way designers of languages like Java, Python or C# would approach new syntax. I'm not sure there's much way to bridge our perceptions. I do agree though that import "M" as X; Is somewhat ambiguous between a |
There's a few things here. Is this syntax confusing? I am inclined to say "yes" and I think most of the TypeScript team would agree with you on this. It was not well-received when we reviewed the proposal the committee was working on. Will the ES committee change this later? Absolutely not, at least not in a way that changes the semantics of a supported syntax. The ES6 draft is basically at the last stage before final and once it has some behavior in runtimes, that is not going to change. What should TypeScript do about it? It's not like we're going to diverge from ES6 behavior, and adding another syntax variant would almost certainly be more confusing rather than less. Even if the ES6 module syntax is nuts, it's a kind of nuts you can learn and eventually reason about. It's not in our goals to create lots of syntactic variations on existing constructs. |
(my original comment on the ES6 modules thread: #2242 (comment))
Here's a challenge: ask the average programmer what this soon-to-be-valid TypeScript code does:
My guess is that 90% of the respondents will tell you it would probably import some member (or "export", in the official terminology) called
X
from a module calledM
. Now what about this?Well, that would probably import member X and the whole module (represented by
*
) aliased as Z fromM
. Then show them this:And this:
My guess? they'll answer "the same?" - meaning it imports
X
as itself andY
with aliasZ
Now here's the real thing: according to the spec, the first example, although appearing quite straightforward, would do something _completely different_ than most people (including myself) would expect. It wouldn't import an export called
X
but instead _alias the default export_ ofM
to the identifierX
.So essentially it would appear to compile and run but later give out unexpected and weird run-time errors when
X
is accessed and used with a different semantic meaning. The third example, on the other hand, would import theX
member as expected.The second and forth examples, although very similar in appearance, still suffer from this problem, In the second example
X
will alias the _default_ export, but in the forth it would import the memberX
as expected.So the first example could have been replaced, for instance, by a simpler and more natural syntax such as this:
And the second (not sure if any of this is valid syntax today but certainly could be):
This may not be a TypeScript issue per se, but I cannot understand how anyone would allow such a poorly designed syntax to be introduced to an existing language that's currently quite neat and readable? I believe that as soon as this syntax gets to wider adoption, it would be inevitable to change it. ES would be literally _forced_ to fix this by the masses of developers perplexed by this insanity.
I personally think it's better sooner than later, and now this gaining early adoption within TypeScript and other transpilers, there's going to be actual production code using this, so a price may have to be payed when this is "fixed" later by ES.
Please keep this issue open as I honestly consider this to be a bug. It wouldn't be wise to direct all responsibility to ES as there are some talented people at Microsoft who have been spending years now in designing, developing and implementing a scalable, usable and readable language. It would be demotivating to force them to maintain and support a faulty and confusing syntax such as this (and later spend much time and thought on how to fix it and work around legacy code still making use of the "older" syntax).
The text was updated successfully, but these errors were encountered: