question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Suggestion: Allow ES6 export syntax in namespaces

See original GitHub issue

TypeScript Version: typescript@4.0.0-dev.20200801

Search Terms: namespace, import, export, re-export, module

Code

import { Point } from "./Point";

export type Line = {
  readonly p1: Point;
  readonly p2: Point;
  readonly points?: readonly [Point, ...(readonly Point[])];
};

export namespace Line {
  export { Point } from "~/Point"; // TS says "Export declarations are not permitted in a namespace"
  // `export { Point };` <-- Should also work.
}

type LinePoint = Line.Point;
// ^ Somehow this actually works, i.e. `LinePoint` equals `Point`

Expected behavior: Exporting from a namespace should mirror ES6 module exports, i.e. export { X }, export { X } from "...", and export * as NS from "..."

The lack of syntax for re-exports makes it very hard to use namespace/type/function merging abilities to represent nice APIs. Here’s an example of what a module could look like if this was allowed…

// User.tsx

import { Admin } from "./Admin";
import { Member } from "./Member";

export type User = Admin | Member;
export type Props = { readonly user: User; };

export function User({ user }: Props) {
  return Admin.isAdmin(user) ? <Admin admin={user} /> : <Member member={user} />;
}

export namespace User {
  export { Admin, Member }; // Nice.
  export const isAuthenticated = (user: User): boolean => true;
}

// Home.tsx

import { User } from "./User";

export function Home({ user }: User.Props) {
  return <User.Admin admin={useAdmin()} />; // An example of what this enables.
}

Actual behavior: TypeScript says “Export declarations are not permitted in a namespace,” even though it actually respects the export declaration outside of the namespace.

Playground Link: https://www.typescriptlang.org/play/#code/HYQwtgpgzgDiDGEAEBBJBvAUEnSIA8YB7AJwBcl4jgoKQkBeJAIhGaRCkutoG5MAvpkyhIsBMgBCGbLgLFyGVEgH8hmKjQr5GSSQDoU+kLyA

Related Issues: https://github.com/microsoft/TypeScript/issues/20273 This issue showcases some of the syntax gymnastics needed to get around this issue.

https://github.com/microsoft/TypeScript/issues/4529 https://github.com/microsoft/TypeScript/issues/4529#issuecomment-140932811 More examples of verbose workarounds.

https://github.com/microsoft/TypeScript/issues/38041#issuecomment-616807133 @rbuckton Provides a nice example of what this could look like if enabled.

https://github.com/microsoft/TypeScript/issues/38041#issuecomment-662142857 My comment with another motivating example after the issue was closed.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:11
  • Comments:15

github_iconTop GitHub Comments

8reactions
cruhlcommented, Aug 17, 2020

Here’s more “in the wild” code I found showing the syntax noise needed to get around this…

// This file is "./Claim/index.ts"

import * as Details_ from "./Details";
import * as Dashboard_ from "./Dashboard";
import * as Create_ from "./Create";
import * as Admin_ from "./Admin";

import { API } from "../API";

export type Claim = API.GetClaimQuery["getClaim"];
export namespace Claim {
  export const Create = Create_;
  export const Details = Details_;
  export const Dashboard = Dashboard_;
  export const Admin = Admin_;
}

Here’s what it could look like…

import { API } from "../API";

export type Claim = API.GetClaimQuery["getClaim"];
export namespace Claim {
  export * as Create from "./Create";
  export * as Details from "./Details";
  export * as Dashboard from "./Dashboard";
  export * as Admin from "./Admin";
}

Or even…

import * as Details from "./Details";
import * as Dashboard from "./Dashboard";
import * as Create from "./Create";
import * as Admin from "./Admin";

import { API } from "../API";

export type Claim = API.GetClaimQuery["getClaim"];
export namespace Claim {
  export { Details, Dashboard, Create, Admin };
}
5reactions
cruhlcommented, Jan 12, 2022

@andrewbranch I apologize if tagging you directly isn’t the right move, let me know if that’s the case, but I was wondering if you could provide some insight since you recently closed another related issue.

This is still something I believe would be a useful change and I’m eager/willing to champion/help in whatever way I can. Any pointers for moving the issue forward? Thanks in advance!

Read more comments on GitHub >

github_iconTop Results From Across the Web

How do I use namespaces with TypeScript external modules?
You can by having a "wrapper" module that imports and re-exports everything of interest to consumers of your library. But again, using a...
Read more >
16. Modules - Exploring JS
The ES6 module standard has two parts: Declarative syntax (for importing and exporting); Programmatic loader API: to configure how modules are loaded and...
Read more >
Employing “Namespaces” in TypeScript to encapsulate your ...
The syntax to export values from a namespace is as simple as putting export before a declaration whether it is a let ,...
Read more >
Auto Import | IntelliJ IDEA Documentation - JetBrains
See importing unbound namespaces for details. ... When you are using ES6 modules in a browser that requires full file names, for example, ......
Read more >
Understanding (all) JavaScript module formats and tools
The above counter module in ES6 import/export syntax can be converted to the ... namespace Counter { let count = 0; export const...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found