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

Add new syntax to import namespaces #2956

Closed
mikehaas763 opened this issue Apr 29, 2015 · 14 comments
Closed

Add new syntax to import namespaces #2956

mikehaas763 opened this issue Apr 29, 2015 · 14 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@mikehaas763
Copy link

Opening this separate issue as suggested by @mhegazy in the PR mentioned below. I'm not the most informed on this issue but I am opening it because I do not want it to get lost/forgot.

Quoting @mhegazy here:

@ahejlsberg proposed a import * from "mod" syntax to do that a while back. and in this case it would be import * from namespace. the problem here is it makes it harder to do a syntactic transformation on a single file, as the compiler needs to have the full program information to know how things should be qualified. it is something that we are looking into, i would recommend filing a new issue for this instead of having the discussion on this PR.

The PR is just renaming internal modules to namespaces to avoid any confusion with ES6 modules. this is something we got feedback for regularly from customers.

Now that TypeScript has renamed internal modules to namespaces and has the namespace keyword (PR #2923) it would be nice to be able to import a namespace and then have access to the types defined on that namespace. Would this essentially just be a new syntax to do what /// <reference path> does?

What are the obstacles and concerns for this feature?

@danquirk danquirk added the Suggestion An idea for TypeScript label Apr 29, 2015
@NoelAbrahams
Copy link

@mhegazy,

the problem here is it makes it harder to do a syntactic transformation on a single file

I am assuming this means generating the AST from the source file.

as the compiler needs to have the full program information to know how things should be qualified.

How does the compiler currently deal with types defined outside of the file? What problem does import * from namespace introduce here?

@mhegazy
Copy link
Contributor

mhegazy commented Apr 30, 2015

There are two workflows that the TypeScript compiler supports today:

  1. Full program compilation:
    This is your normal command line compilation, passing all files, and the compiler makes an assumption that they are the "world". In this mode anything is possible :D as the compiler has loaded all files, crunched all declarations and understands what things mean, or it generates an error.
  2. Single module transpilation:
    This is a module loader in the browser that wants to do transpilation on the fly. This has been discussed early on in the ES6 module proposal for loader pipeline, that was not ratified as part of the ES6 spec. This however, is a useful work flow, and it is used in es6-module-loader, JSPM, and even in atom to load extensions.
    In this mode, the compiler is expected to get a single file, transpile it, and always emit the correct JS code. This means that any type-directed emit would break. All transformations done by the compiler should be restricted to syntactic transformation that do not require type information.
    In general TypeScript has not done type-directed emit; the main place where this is not true is internal modules/namespaces as unqualified member access is allowed. obviously you can not do that as a syntactic transformation.In external modules we do not have this problem as modules introduce a new scope, and can not pollute the global namespace.
    More details about this can be found in Support single-module transpilation mode #2499.

In the full program compilation mode, it is not an issue. it is just an extension on how we do namespaces today. but in the second it is going to work.

So something like:

// file: a.d.ts
declare namespace A {
    function helper(): void;
}
// file: b.ts
import * from A;
helper();

and expect the output to be:

// file: b.js
A.helper();

would not work if the compiler only looked at b.ts in without having consumed a.d.ts first.

We have the option to enable it only for the first mode. the problem here is forking the language into two dialects, where some things work in one but not the other.

@mikehaas763
Copy link
Author

@mhegazy Thanks for the info. That's something I was trying to work out in my head as to how it would work without forking the language and I'm not really sure that there is a good way to do it.

I guess the argument could be that with namespaces the /// <reference comment essentially is a part of the language and so it is already forked. Maybe continuing down that forking paradigm isn't a great idea.

@asgerhallas
Copy link

@mhegazy Do you know, if this has been given any further consideration? :)

@mhegazy
Copy link
Contributor

mhegazy commented Sep 25, 2015

It keeps comming up, but no more use cases/proposals other than what is discussed earlier in this issue.

@mhegazy mhegazy added the Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. label Dec 9, 2015
@mpseidel
Copy link

+1 I would love a feature like this. As my code files grow and I use decorators more and more my import {BaseClass,decorator,otherDecorator,helper} from 'somemodule' gets longer and longer. import * as x from 'somemodule' isnt that pretty either

@listepo
Copy link

listepo commented Feb 18, 2016

+1

@MgSam
Copy link

MgSam commented Mar 13, 2018

I've been writing more TypeScript lately after some time not using it. The import statements are, by far, the most painful part of the language.

  1. First, unqualified imports are absolutely needed.

import * from 'file';

I don't see any reason why TypeScript requires an alias. It knows all the types coming out of that file; therefore it can statically check for conflicts with other types that have been imported. If someone has some additional module loaded at runtime outside of this- well then they're already stepping outside the type system and that's their own responsibility to make sure there are no conflicts.

  1. Even better, please just create a damn project file already that references every TypeScript file in the project. It is absurd having all this spaghetti code where one file points to another points to another points to another. Why can every other language use project files but not TypeScript?

People have tried to simulate this with hacks like so-called "barrel files", but those cause all kinds of problems with circular references when used with certain tools. The solution is first-class compiler support for actual project files.

It looks like you guys are exploring other import changes so I strongly urge you to explore fixing this painful area of the language as well.

The current status quo are brittle file references that break if you move anything, having to constantly update import statements to add additional types, and overall a ton of wasted time. Please improve this awful situation.

@mikehaas763
Copy link
Author

I don’t remember exactly what was going through my head when I first opened this issue. TypeScript is just a superset of JavaScript. So, there are no namespaces. The namespace feature in TS is just an artifact of being around before the ES module spec stabilized (pretty sure).

  1. I believe you can do that, at least via the syntax import * as thing from ‘thing’; which is an import I use often at work

  2. something like that does exist, it’s the tsconfig file. Better yet, you can use a glob to match multiple files at the same time

@MgSam
Copy link

MgSam commented Mar 13, 2018

  1. Yes, you have to qualify the import via an alias. Which is very annoying and unnecessarily verbose. And say you're importing types from 30 different files (which happens all the time in a large project)- having an alias for each file is not practical. Which means that for every type, you're constantly adding types to import statements via quick fixes.

  2. I believe tsconfig just tells the compiler "compile these files". It doesn't provide any mechanism for files to reference modules from another file without using a path. Individual files should not have to know where on the filesystem the types they want are. They should be referencing them by the name of the module, not the path of the file.

Bottom line, I want import statements to be as simple as:

import * from MyProject.Components;
import * from MyProject.Utilities;

Where are MyProject.Components located? My file shouldn't know or care where. The project file and compiler should take care of that. Hardcoding paths guarantees breakages upon refactoring (which is exactly what TypeScript was designed to help avoid). "Barrel files" are a hack people came up with to avoid this, but they have many problems themselves.

@ahejlsberg
Copy link
Member

@MgSam I understand how this could be useful, but it runs directly counter to TypeScript's design goal of being just ECMAScript with type annotations. In the early days of the project we added some extensions outside of the type system (e.g. enums and namespaces), but at this point we're firmly committed to tracking ECMAScript and TC39 in the core language. That's really the place you should advocate for this feature.

@RyanCavanaugh RyanCavanaugh added Out of Scope This idea sits outside of the TypeScript language design constraints and removed Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. labels Mar 13, 2018
@MgSam
Copy link

MgSam commented Mar 13, 2018

@ahejlsberg I appreciate that being "JavaScript with types" is a design goal, but I think in reality TypeScript has never been just that. It originally was a place to try out features long before they ever came near to being part of ECMAScript, the type system just being the most prominent example.

Even the most basic features like classes and lambdas were in TypeScript long before it was ever guaranteed to be added to ECMAScript. I remember in some of your first talks about TypeScript how you mentioned that you were adding these things because hopefully they'll be added to JS, but who knows if that'll ever happen.

More recently, you guys have even done more non-type related stuff like down-level async/await emit, React support, and decorators.

Adding new stuff into TypeScript is valuable not just for users immediate productivity, but also, by your own words, helps inform the design of the features when they do eventually (some day) come up in the ECMAScript committee meetings.

With WebAssembly, the web will soon be a much more crowded place with many other languages able to compile into WebAssembly and run in a browser (including C#!). JavaScript will become less and less relevant- tying yourself to the politics and glacial progress of a standards committee is the last thing you should be doing now.

Waiting on the ECMAScript committee to make decisions is hamstringing the evolution of the language, hurting users, and ultimately risking the continued relevance of TypeScript. I think exhibit one to back up that claim is the safe navigation operator. It's far and away the most popular feature request ever suggested for the language, has been asked for for at least four years, would yield massive benefits to writing the language, is relatively simple to implement (as far as language features go) and yet is not implemented because its stuck in standards hell with TC39. Even your friends on the Angular team gave up waiting and implemented the operator themselves.

And speaking of the Angular team, you should reflect on how you barely avoided having them fork and make their own typed-superset of JavaScript. And you did this in large part by being willing to add decorators prior to their inclusion in ECMAScript. You guys failed to accomplish the same with Facebook. Having a rule that you cannot organically add non-type related features practically guarantees that this will inconvenience some other company (large or small) eventually and result in even further fragmentation of the ecosystem as they too make their own forks.

I really hope the language design team reassess this new mantra of "we're not adding anything until it's approved by TC39". It's not doing you guys or your users any favors.

@RyanCavanaugh
Copy link
Member

Thanks for the feedback - we're continually evaluating the right balance between tracking TC39 and the convenience of the language.

@NoelAbrahams
Copy link

After 5 years of TypesScript and a 100K plus code-base I truly believe that the namespace approach is superior to (external) modules.

The world will come to this realisation one day.

😞 🔫

@microsoft microsoft locked and limited conversation to collaborators Jul 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

10 participants