Lets say we have the following 2 external modules in TypeScript:
export module My.Services.Common
{
export class Helper
{
//...
}
}
and
export module My.Services
{
export class Connection
{
//...
}
}
Now in my app.ts I would like to use both Connection and Helper classes. What I want to achieve is similar to the following code in C#:
using My.Services;
using My.Services.Common;
Or at least just
using My.Services;
But it looks like I cant work at the same time with both Helper and Connection. If I write:
import {My} from './services/common/Helper';
import {My} from './services/Connection;
Leads to error "duplicate identifier 'My'". That is logical though. So my question is how can I consume different classes from the same (or nested) modules?
My personal view on this is to break away from what you see in C# or Java (which maps more closely to internal modules) and treat it more like the external modules you are using...
Step 1. Ditch the module
keyword. The file is a module already.
Step 2. Provide a non-dotted alias when you import.
Step 3. You can now import everything, '*', or specific classes when you import.
./services/common.ts
export class Helper
{
//...
}
./services.ts
export class Connection
{
//...
}
./app.ts
import * as Services from './services'
import { Connection } from './services/common'
var x = new Services.Helper();
var y = new Connection();
You can import multiple members from a module too:
import { Connection, Example } from './services/common'
var y = new Connection();
var z = new Example();
To add to Steve's good answer, since I've already drawn the ASCII art: The top-level object exported from this module, My
, doesn't merge with any other object from other files named My
. The only thing the My.Services.Common
module achieves is making it more annoying to import Helper
, because you have to fully qualify its name even though there's nothing else in there.
What you think you've done:
/-My--------------------\
| /-Services---------\ |
| | /-Common---\ | |
| | | [Helper] | | |
| | \----------/ | |
| | | |
| | [Connection] | |
| \------------------/ |
\-----------------------/
What you've actually done:
/-My---------------\ /-My---------------\
| /-Services-----\ | | /-Services-----\ |
| | /-Common---\ | | | | [Connection] | |
| | | [Helper] | | | | \--------------/ |
| | \----------/ | | \------------------/
| \--------------/ |
\------------------/
This is like having an organization system in your house where you have a dozen shoeboxes, each with a single smaller box inside it, each with a smaller box inside that one. The nested boxes provide no organizational benefit over the shoeboxes!
I have found another approach for tackling this organisation problem.
To go back to ASCII art (ᵔᴥᵔ)
My folder structure is so:
|
|-- myawesomemodule
| |
| |-- myawesomeclass.ts
| |-- myevenmoreawesomeclass.ts
| |-- myawesomemodule.ts
|
|-- myevenmoreawesomemodule
| |-- myotherclass.ts
| |-- myanotherclass.ts
| |-- myevenmoreawesomemodule.ts
|
index.ts
In myawesomemodule.ts
, I do:
export {MyAwesomeClass} from './myawesomeclass'
export {MyEvenMoreAwesomeClass} from './myevenmoreawesomeclass'
Similarly in myevenmoreawesomemodule.ts
, I do:
export {MyOtherClass} from './myotherclass'
export {MyAnotherClass} from './myanotherclass'
And finally at the root level in index.ts
, I do:
import * as MyAwesomeModule from "./myawesomemodule/myawesomemodule";
import * as MyEvenMoreAwesomeModule from "./myevenmoreawesomemodule/myevenmoreawesomemodule";
export {MyAwesomeModule};
export {MyEvenMoreAwesomeModule};
Now I can ship this module off to a consumer, pack as NPM etc.
From a consumer, I do:
import MyPackage = require("mypackage"); //assuming you did npm pack
OR
import * as MyPackage from "./path/to/index" //assuming you didn't
Then I refer to my class names so:
let instance = new MyPackage.MyAwesomeModule.MyAwesomeClass();
I find this approach a bit better than exposing all my classes in a big module at the root level.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With