Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Importing typescript from external node modules

I want to split my application into different node modules and have a main module which builds all other modules as well and I want to use typescript with es6 modules.

Here is my planned project structure:

  • main
    • node_modules
      • dep-a
      • dep-b
  • framework
    • interfaces
      • IComponent.ts
  • dep-a
    • components
      • test.ts
    • node_modules
      • framework
    • index.ts
  • dep-b
    • node_modules
      • framework

I want to be able to define interfaces in framework which can be consumed in dep-a, dep-b and main.

How do I set up this correctly? Can I compile everything from my main-module? Do I need to create different bundles for framework, dep-a, ... and another typing file? What is the best approach for this?

I already set up some test files and folders and used npm link to link the dependencies and webpack to bundle the files and I am always running into issues with files not being found:

error TS2307: Cannot find module 'framework/interfaces/IComponent'

and

Module not found: Error: Cannot resolve 'file' or 'directory' ./components/test
like image 316
david Avatar asked Mar 15 '23 00:03

david


2 Answers

TL;DR generate declarations for the modules using declaration: true in tsconfig.json and specify the file for your generated typings in the typings entry of the package.json file

framework

Use a tsconfig file similar to this:

{
       "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "declaration": true,
        "noImplicitAny": true,
        "removeComments": true,
        "outDir": "dist",
        ...
    },
    "files": [
         ...
    ]
}

The important bit is declaration: true which will generate internal declarations in the dist directory

Assuming there is an index.ts file which (re)exports all the interesting parts of framework, create a package.json file with a main and typings entry pointing to, respectively, the generated js and the generated declaration, i.e.

{
   "name": "framework",
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",
   ...
 }

Commit this module to a git repo, say bitbucket at : "https://[email protected]/myUser/framework.git"

dep-a

in package.json create a dependency to framework

{
    "dependencies": {
        "framework":     "https://[email protected]/myUser/framework.git"
    },
}

That is it.

import * from 'framework'

will pull the dependency with the typings, automatically

Obviously, it is possible to do with dep-a what was done with framework i.e. generate the declarations, update package.json and use dep-a as a module with embedded typings in main

note: a file URL will do in package.json/dependencies if you do not want go to via an external git repo

like image 115
Bruno Grieder Avatar answered Mar 23 '23 11:03

Bruno Grieder


What arrived in TypeScript 1.6 is typings property in package.json module. You can check the relevant issue on GitHub.

So assuming you want to create separate modules ( dep-a, framework ). You can do the following :

main.ts                 // (1)
package.json            // (2)
node_modules/
  dep_a/                
    index.js            // (3)
    index.d.ts          // (4)
    package.json        // (5)
    node_modules/
      framework/ 
        index.js        // (6)
        index.d.ts      // (7)
        package.json    // (8)

So let's see what you have in your files :

//(1) main.ts
import * as depA from "depA";

console.log(depA({ a : true, b : 2 }) === true) // true;

//(2) package.json
{
  name: "main",
  dependencies: {
    "dep_a" : "0.0.1"
  }
  ...
}

For depA

//(3) dep_a/index.js
module.exports = function a(options) { return true; };

//(4) dep_a/index.d.ts;

import * as framework from "framework";

export interface IDepA extends framework.IFramework {
   a : boolean
}

export default function a(options: IDepA) : boolean; 

//(5) dep_a/package.json
{
  name: "dep_a",
  dependencies: {
    "framework" : "0.0.1"
  },
  ...
  typings : "index.d.ts" // < Magic happens here
}

For framework

//(6) dep_a/node_modules/framework/index.js
module.exports = true // we need index.js here, but we will only use definition file

//(7) dep_a/node_modules/framework/index.d.ts;

export interface IFramework {
   b : number;
}

//(8) dep_a/node_modules/framework/package.json
{
  name: "framework"
  ...
  typings : "index.d.ts"
}

What I don't include in this answer ( for clarity ) is another compilation phase, so you could actually write the modules ( dep_a, framework ) with typescript and then compile them to index.js before you use them.

like image 21
drinchev Avatar answered Mar 23 '23 11:03

drinchev