Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript ES6 module syntax with ambient d.ts module

Tags:

typescript

tsc

So lets imagine I have a 50 file module, and each one contains:

export class <SomeClassName> { /* content */ }

Then, I create a root file to simplify usage by re-exporting all the files. So it would look like:

export * from "./src/some-class-1";
export * from "./src/some-class-2";
export * from "./src/some-class-3";
// etc

Then, I run it through TSC to do a "common" module targeting "es5" with descriptor output.

So far so good. I have my package.json with name my-module target the outputted index.js as the entry point for my module. So I now go and decide to consume this module in another typescript project.

So I do the npm install for it (lets pretend) npm install my-module and it all pulls in, so I now have the d.ts files which were generated, and I have the actual commonjs module so I can use it all. Everything seems to be fine.

Then comes the problem. I then decide to make use of the module:

import {SomeClass1} from 'my-module'

It blows up as in the TS world, it doesn't know what my-module relates to, as if we go back and look at the index.js which was outputted, it does not contain an ambient module.

So here is the problem, common modules generally use the package.json as the point of reference when including module names, however TS uses the d.ts files. So then I thought well ok, I need to wrap my re-exports in index.ts in a module, so I try:

export module "my-module" { /* all other re-exports */ }

But turns out you can only use string module names for ambient modules, and you can only put them within d.ts files, however my d.ts file is generated from the existing codebase.

So here is my dilemma, I can manually go in and add a declare module "my-module wrapper to my d.ts, but it's not very automated, or I do like the blog posts with ES6 syntax do and reference the file relatively which would end up with lots of import {blah} from "../node_modules/my-module/dist/index", which hopefully we can all agree is a bit silly.

So I cannot find any sort of other approach which would work in the automated world, as all blog posts and docs on this subject when you use the ES6 syntax all use relative file imports, not imports from when the whole thing has been compiled and shared via d.ts files.

So is there a way here to wrap my re-exports in a textual module name? Or at least tell the index.d.ts to be contained with an ambient module? (as remember it will output a d.ts file for every file in the project, but we only care about importing the module via the index.d.ts as that re-exports everything).

like image 982
Grofit Avatar asked Aug 13 '15 08:08

Grofit


2 Answers

Right now you still need to use another tool to generate a single .d.ts file for your package. There are a few tools that can do that:

  • dts-generator
  • dts-bundle
  • autodts - aims to make it easier to consume the generated .d.ts in packages published to NPM

Personally I'm using a customized version of dts-generator that makes use of tsconfig.json and works with nightly TypeScript builds. You can see a .d.ts that it generated for one of my packages over here.

like image 149
Vadim Macagon Avatar answered Oct 10 '22 07:10

Vadim Macagon


Ok I finally have it working, well for CommonJS at least.

Now with typescript 1.6 changes the TS module resolution will check node_modules folder for an index.d.ts file. So I have basically added this file at the end of the build process which points to my dist/definitions/index.d.ts file which includes all the exports.

This way you can do an import like import * from "my-module" and as long as in your node_modules folder you have a my-module folder with an index.d.ts it will basically treat everything within that index as a module.

I will happily change the answer to another one if anyone else gets a better solution which works for all and not just commonjs but for the moment it is enough to get me going and hopefully it may help someone else.

like image 43
Grofit Avatar answered Oct 10 '22 07:10

Grofit