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

Support “Arbitrary module namespace identifier names” #40594

Open
5 tasks done
ExE-Boss opened this issue Sep 16, 2020 · 13 comments · May be fixed by #49297
Open
5 tasks done

Support “Arbitrary module namespace identifier names” #40594

ExE-Boss opened this issue Sep 16, 2020 · 13 comments · May be fixed by #49297
Labels
Domain: ES Modules The issue relates to import/export style module behavior Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". ES Next New featurers for ECMAScript (a.k.a. ESNext) Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Help Wanted You can do this Suggestion An idea for TypeScript

Comments

@ExE-Boss
Copy link
Contributor

ExE-Boss commented Sep 16, 2020

Search Terms

  • Arbitrary module namespace identifier names
  • Arbitrary module namespace identifiers
  • Arbitrary module identifier names
  • Arbitrary module identifiers
  • Arbitrary module identifier
  • Arbitrary export names
  • Arbitrary export identifiers
  • string export names
  • string exports

Suggestion

Implement support for tc39/ecma262#2154.

Use Cases

This is necessary for WASM module integration.

This would also allow typing @types/webidl‑conversions without needing to use export =.


For transpiled modules, this can already be supported, since it’s just creation of arbitrary properties on the CommonJS exports object, but native modules will require module: "ESNext".

Examples

See tc39/ecma262#2154

// @showEmit
// @filename: module.d.ts
export const foo: unknown;

declare const some_imports: unknown;
export { some_imports as "some imports" };

declare const another_imports: unknown;
export { another_imports as "another imports" };

declare const extra_imports: unknown;
export { extra_imports as "extra imports" };

declare const rest_exports: unknown;
export { rest_exports as "rest exports" };

// @filename: index.ts
import { "some imports" as foo } from "./module.js";

export { foo as "some exports" } from "./module.js";
export { "another imports" as "another exports" } from "./module.js";
export { "rest exports" } from "./module.js";
export { "extra imports" as extra_imports } from "./module.js";

export * as "star exports" from "./module.js";

Workbench Repro

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Related issues

@DanielRosenwasser DanielRosenwasser added ES Next New featurers for ECMAScript (a.k.a. ESNext) Waiting for TC39 Unactionable until TC39 reaches some conclusion labels Sep 16, 2020
@ExE-Boss
Copy link
Contributor Author

ExE-Boss commented Oct 22, 2020

Note that Babel now has support for this: babel/babel#12091

@typescript-bot typescript-bot added the Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros label Feb 16, 2021
@DanielRosenwasser DanielRosenwasser added Domain: ES Modules The issue relates to import/export style module behavior Committed The team has roadmapped this issue and removed Waiting for TC39 Unactionable until TC39 reaches some conclusion labels May 9, 2021
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 4.4.0 milestone May 9, 2021
@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented May 9, 2021

tc39/ecma262#2154

import { "😊" as yay } from "...";

yay();

export { yay as "🦈" };

The above code should be supported.

The minimum viable product should have tests for:

  • esnext module output
  • es2015 or similar module output just to get an error
  • --declaration emit
    • Specific declaration emit where the compiler might generate import() type syntax.
  • Quick info, and error message tests where we might generate import() type syntax
  • Completions in import {} and export {} lists
  • Go-to-definition

It is likely that we would never try to emit our own import() type syntax.

@DanielRosenwasser DanielRosenwasser added the Suggestion An idea for TypeScript label May 9, 2021
@andrewbranch andrewbranch added the Rescheduled This issue was previously scheduled to an earlier milestone label Aug 30, 2021
@evanw
Copy link

evanw commented Sep 28, 2021

Is it planned for this to work with TypeScript types as well as values? For example, I'd expect the following to be valid as well:

import type { 'a' as b } from 'foo' 
import { type 'a' as b } from 'foo' 

export type { a as 'b' }
export { type a as 'b' }
export { type 'a' } from 'foo' 
export { type 'a' as b } from 'foo' 
export { type a as 'b' } from 'foo' 
export { type 'a' as 'b' } from 'foo' 

I'm wondering because esbuild supports both TypeScript and arbitrary module namespace identifier names, so it has to deal with this somehow. Right now I'm moving forward assuming that it will eventually be supported for types as well but it would be good to clarify this.

@andrewbranch
Copy link
Member

andrewbranch commented Oct 1, 2021

@evanw I’m pretty sure your examples above will “just work” unless we explicitly disallow them, and I don’t see an immediate reason to do that. The syntax above would certainly parse. Just out of curiosity, what’s the impact of this on esbuild?

@andrewbranch
Copy link
Member

andrewbranch commented Oct 1, 2021

@DanielRosenwasser should this actually be milestoned right now? It’s a bit hard to tell the status of the spec change, but it looks kinda stuck.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Oct 1, 2021

Good call, I assumed it would be an open-and-shut normative PR but it looks like it hasn't been updated for a while; let's hold off until tc39/ecma262#2154 is actually merged.

@andrewbranch andrewbranch added Waiting for TC39 Unactionable until TC39 reaches some conclusion and removed Committed The team has roadmapped this issue Rescheduled This issue was previously scheduled to an earlier milestone labels Oct 1, 2021
@andrewbranch andrewbranch removed this from the TypeScript 4.6.0 milestone Oct 1, 2021
@ExE-Boss
Copy link
Contributor Author

ExE-Boss commented Oct 4, 2021

@andrewbranch

@DanielRosenwasser should this actually be milestoned right now? It’s a bit hard to tell the status of the spec change, but it looks kinda stuck.

Note that this is already implemented in V8, SpiderMonkey, and JavaScriptCore;

see tc39/ecma262#2154 (comment):

For the [needs implementation] label: this now works in Node.js 16 (and thus Chrome 90 I believe).

EDIT: This works also in JSC and SM.

~ via ⬢ v16.0.0 
➜ eshost -x 'import(`/home/nicolo/test.js`).then(JSON.stringify).then(print)'
#### ChakraCore

SyntaxError: Syntax error

#### Hermes

SyntaxError: Invalid expression encountered

#### JavaScriptCore
{"😊":2}

#### Moddable XS


#### SpiderMonkey
{"😊":2}

#### V8
{"😊":2}

@ExE-Boss
Copy link
Contributor Author

ExE-Boss commented Nov 11, 2021

@andrewbranch @DanielRosenwasser
tc39/ecma262#2154 has now been merged.

@andrewbranch andrewbranch removed the Waiting for TC39 Unactionable until TC39 reaches some conclusion label Nov 11, 2021
@andrewbranch
Copy link
Member

andrewbranch commented Nov 11, 2021

@DanielRosenwasser do we want to make this Help Wanted for 4.6? Kind of surprised we don’t have a community PR already 😁

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Nov 15, 2021

I suppose so - I would urge a bit of caution to external contributors because I'm sure an implementation needs to now handle a bunch of edge-cases around rename, find-all-refs, etc. Also, it might be worth erroring if the module target isn't high enough? Unclear to me right now.

@DanielRosenwasser DanielRosenwasser added Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Help Wanted You can do this labels Nov 15, 2021
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 4.6.0 milestone Nov 15, 2021
@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 13, 2022

👋 Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.


Issue body code block by @ExE-Boss

Failed: -

  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Duplicate identifier '(Missing)'.
  • Duplicate identifier '(Missing)'.
  • Cannot find module 'some imports' or its corresponding type declarations.
  • Cannot find name 'as'.
  • Cannot find name 'foo'.
  • Cannot find name 'from'.
  • Cannot find module 'some exports' or its corresponding type declarations.
  • Cannot find name 'from'.
  • Cannot find name 'as'.
  • Cannot find name 'from'.
  • Cannot find name 'from'.
  • Cannot find name 'as'.
  • Cannot find name 'extra_imports'.
  • Cannot find name 'from'.
  • Cannot find module 'star exports' or its corresponding type declarations.
  • Cannot find name 'from'.
  • Identifier expected.
  • ';' expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • ';' expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • ';' expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • ';' expected.

Emit:
as;
foo;
from;
"./module.js";
export { foo as  } from "some exports";
from;
"./module.js";
as;
"another exports";
from;
"./module.js";
from;
"./module.js";
as;
extra_imports;
from;
"./module.js";
export * as  from "star exports";
from;
"./module.js";

Historical Information
Version Reproduction Outputs
4.4.2, 4.5.2, 4.6.2

Failed: -

  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Duplicate identifier '(Missing)'.
  • Duplicate identifier '(Missing)'.
  • Cannot find module 'some imports' or its corresponding type declarations.
  • Cannot find name 'as'.
  • Cannot find name 'foo'.
  • Cannot find name 'from'.
  • Cannot find module 'some exports' or its corresponding type declarations.
  • Cannot find name 'from'.
  • Cannot find name 'as'.
  • Cannot find name 'from'.
  • Cannot find name 'from'.
  • Cannot find name 'as'.
  • Cannot find name 'extra_imports'.
  • Cannot find name 'from'.
  • Cannot find module 'star exports' or its corresponding type declarations.
  • Cannot find name 'from'.
  • Identifier expected.
  • ';' expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • ';' expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • ';' expected.
  • Declaration or statement expected.
  • Unexpected keyword or identifier.
  • Identifier expected.
  • ';' expected.

Emit:
as;
foo;
from;
"./module.js";
export { foo as  } from "some exports";
from;
"./module.js";
as;
"another exports";
from;
"./module.js";
from;
"./module.js";
as;
extra_imports;
from;
"./module.js";
export * as  from "star exports";
from;
"./module.js";

4.2.2, 4.3.2

Failed: -

  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Identifier expected.
  • Declaration or statement expected.
  • Duplicate identifier '(Missing)'.
  • Duplicate identifier '(Missing)'.
  • Cannot find module 'some imports' or its corresponding type declarations.
  • Cannot find name 'as'.
  • Cannot find name 'foo'.
  • Cannot find name 'from'.
  • Cannot find module 'some exports' or its corresponding type declarations.
  • Cannot find name 'from'.
  • Cannot find name 'as'.
  • Cannot find name 'from'.
  • Cannot find name 'from'.
  • Cannot find name 'as'.
  • Cannot find name 'extra_imports'.
  • Cannot find name 'from'.
  • Cannot find module 'star exports' or its corresponding type declarations.
  • Cannot find name 'from'.
  • Identifier expected.
  • ';' expected.
  • ';' expected.
  • Declaration or statement expected.
  • ';' expected.
  • Identifier expected.
  • Declaration or statement expected.
  • ';' expected.
  • Identifier expected.
  • ';' expected.
  • ';' expected.
  • Declaration or statement expected.
  • ';' expected.
  • Identifier expected.
  • Declaration or statement expected.
  • ';' expected.
  • Identifier expected.
  • ';' expected.
  • ';' expected.
  • Declaration or statement expected.
  • ';' expected.
  • Identifier expected.
  • ';' expected.
  • ';' expected.

Emit:
as;
foo;
from;
"./module.js";
export { foo as  } from "some exports";
from;
"./module.js";
as;
"another exports";
from;
"./module.js";
from;
"./module.js";
as;
extra_imports;
from;
"./module.js";
export * as  from "star exports";
from;
"./module.js";

@Jack-Works
Copy link
Contributor

Jack-Works commented May 28, 2022

Let me try this but no guarantee I will make it

@Jack-Works
Copy link
Contributor

Jack-Works commented May 29, 2022

Parser and SystemJS/CommonJS emit work now. Still have no idea how I should change the type system to support analyzing that.

@Jack-Works Jack-Works linked a pull request May 29, 2022 that will close this issue
7 tasks
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label May 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: ES Modules The issue relates to import/export style module behavior Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". ES Next New featurers for ECMAScript (a.k.a. ESNext) Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants