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

Re-exporting namespace declarations in ES6 ambient declaration #4336

Open
jbrantly opened this issue Aug 17, 2015 · 10 comments
Open

Re-exporting namespace declarations in ES6 ambient declaration #4336

jbrantly opened this issue Aug 17, 2015 · 10 comments
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@jbrantly
Copy link

Right now many declaration files take this form:

declare namespace MyLib {

}

declare module 'myLib' {
  export = MyLib;
}

However, there doesn't seem to be an equivalent for ES6 modules:

declare module 'myLib' {
  export default MyLib; // this works for exporting the default, but other exported items in MyLib are not considered to be named exports of the ES6 module
  export * from MyLib; // this is essentially what I'm trying to accomplish
}
@mhegazy
Copy link
Contributor

mhegazy commented Aug 17, 2015

so why use export = then?

@jbrantly
Copy link
Author

@mhegazy Sorry, I didn't understand your comment. Could you clarify?

The export = MyLib pattern is useful for making a module from a namespace without having to actually redeclare everything. The goal of the issue, in words, would be to allow making an ES6 module from a namespace without having to actually redeclare everything.

@mhegazy
Copy link
Contributor

mhegazy commented Aug 17, 2015

We have talked about 1. allowing external modules to access the global namespace (#4166) and 2. extending export * to namespaces. none has enough traction though.

what is the proposal here?

@jbrantly
Copy link
Author

I don't think #4166 applies here. I'm not trying to access the global namespace. I'm trying to re-export the exported declarations of an existing namespace.

Extending export * to namespaces might be applicable but it's hard to tell without more context on what you mean.

As far as a proposal, I would suggest new syntax for ambient ES6 module declarations which allows re-exporting declarations from an existing namespace. Let me first illustrate with an example that already works:

declare module "someLib" {
  export var a: string;
}

declare module "myLib" {
  export * from "someLib";
  export var b: string;
}

In that example, export * from "someLib" re-exports all exports from "someLib". Copied from #2242:

An export * declaration can be used to re-export all exports of another module. This is useful for creating modules that aggregate the exports of several other modules.

export function transform(s: string): string { ... }
export * from "./mod1";
export * from "./mod2";

An export * doesn't re-export default exports or exports with names that are already exported from the current module. For example, the transform export in the module above hides any transform export in the re-exported modules.

My proposal would be the take that same concept and allow it for namespaces as well:

declare namespace SomeLib {
  export var a: string;
}

declare module "myLib" {
  export * from SomeLib; // <-- this is the new syntax
  export var b: string;
}

Looking at the spec, I don't think there's anything exported from a namespace that can't also be exported from a module. In fact, namespace seems to be a subset of module:

AmbientExternalModuleElement:
  AmbientModuleElement
  ExportAssignment
  export ExternalImportDeclaration

Assuming that's the case, export * from SomeLib seems reasonable.

The use case for this is to simplify writing declaration files for existing ES6 libraries (see #4337).

@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Aug 17, 2015
@e-cloud
Copy link
Contributor

e-cloud commented Dec 3, 2016

(Re)exporting namespaces or interfaces is really reasonable.


current status

You can use the follow style:

a.d.ts

export = class A {
}

index.d.ts

export import A = require('./a')

However, you can't use it in a namespace which is incompatible with scene 3

And it usage is quite limited.


possible scene of re-exporting

For example, I may define several definiation files, assume the library name is MyLib:

a.d.ts

export function AFunc(): void

b.d.ts

export function BFunc(): void

scene 1 (re-export namespace as sub namespace)

index.d.ts (MyLib definition)

export * as LibA from './a'
export * as LibB from './b'

index.tests.ts

import * as MyLib from 'MyLib'
MyLib.LibA.AFunc()
MyLib.LibB.BFunc()

scene 2 (merge the namespaces)

index.d.ts (MyLib definition)

export * from './a'
export * from './b'

index.tests.ts

import * as MyLib from 'MyLib'
MyLib.AFunc()
MyLib.BFunc()

scene 3 (normal for node.js modules)

index.d.ts (MyLib definition)

declare namespace MyLib {
    export * as LibA from './a'
    export * as LibB from './b'
}

export = MyLib

index.tests.ts

import MyLib = require('MyLib')
MyLib.LibA.AFunc()
MyLib.LibB.BFunc()

scene 4 (like scene2 in scene3)

...

@raveclassic
Copy link

raveclassic commented Jan 16, 2017

Any considerations on this?
I'm trying to expose some of the codebase with es6-modules as a global object. This object is constructed from nested namespaces. The problem is that most of the things to be exposed are in es6 modules and I just can't reexport them from namespace.

Something like the following would be extremely useful:

//foo.ts
export enum Foo {
  Foo,
  Bar
}

export type TFoo = Foo | undefined;

export const FOO = 'FOO';

//global.ts
export namespace TEST {
  export const SOME = 'SOME';
  export namespace Nested {
    export * from './foo.ts'; //error here
  }
}

@FlippieCoetser
Copy link

(re)exporting namespaces using existing export syntax would be helpful.

Exporting

export namespace NameSpace {
    export {foo} from './foo'
}

Allowing the above, could it help getting rid of the annoying Export declaration is not permitted in a namespace error?

Would love to logically organise a large component using namespace and still maintain the ability to expose needed members to the outside...

@G07cha
Copy link

G07cha commented Jun 18, 2017

I'm currently using next workaround for interfaces:

import {foo} from './foo'

export namespace NameSpace {
    export interface Foo extends foo {}
}

This should work for classes as well, the only drawback is the fact that you need to rename variables.

@tdeekens
Copy link

tdeekens commented Jan 3, 2018

I would also align typings with small modules while re exporting them in a accumulating bigger module.

@Griffork
Copy link

Oh! Ok! I came across this issue looking for a solution to this problem, but found later in my travels that there is actually a solution now.
I found 4529 which states that you can do export import Name = Value.

Like so:

import FooTemp = Foo;
export namespace a {
    export import Foo = FooTemp;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

8 participants