Re-exporting namespace declarations in ES6 ambient declaration
jbrantly opened this issue ยท 10 comments
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
}so why use export = then?
@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.
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?
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, thetransformexport in the module above hides anytransformexport 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).
(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(): voidb.d.ts
export function BFunc(): voidscene 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 = MyLibindex.tests.ts
import MyLib = require('MyLib')
MyLib.LibA.AFunc()
MyLib.LibB.BFunc()scene 4 (like scene2 in scene3)
...
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
}
}(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...
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.
I would also align typings with small modules while re exporting them in a accumulating bigger module.
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;
}