Import js file with TypeScript 2.0

Lu4 picture Lu4 · Jul 18, 2016 · Viewed 23.9k times · Source

Abstract

I'm trying to import ".js" file from an external location (i.e. node_modules) I'm trying to do this using commonjs module pattern, however import wouldn't want to work with ".js" file types until I add ".d.ts" file near ".js" file in the same folder.

But the problem is that I wouldn't want to affect any node_modules with my ".d.ts" files. I want it to be located in another folder, separate from node_modules but as soon as I do that, typescript compiler throws an error:

Example

I have the following folder structure:

|- DTS
|   |- y.d.ts
|- main.ts
|- y.js

y.js has the following content

module.export = function (x) {
    console.log(x);
};

y.d.ts has the following content

export interface Y {
    (x): any;
}
declare let y: Y;
export default y;

main.ts has the following content

import * as y from './y'

Now when I'm trying to compile main.ts with:

tsc -m commonjs -t ES2015 main.ts

I will get an error:

x.ts(1,20): error TS2307: Cannot find module './y'.

Question

How to import ".js" files and being able to define it's ".d.ts" declarations while having both files located in different locations.


Edit

Here is the link to example project. Be sure to use TypeScript version 2.0 compiler. And the tsc command above to see the error.

Answer

phreed picture phreed · Aug 30, 2016

Note: The official recommendation for proving your type definitions takes a slightly different approach than what is presented below. I believe the approach below is slightly better as the *.d.ts file is practically identical to the final product.

During typechecking (build time) TypeScript works with *.ts files and (mostly) ignores *.js files. Let me offer an example that motivates what (I believe) you are proposing. Suppose there exists a perfectly good JavaScript library that sadly has no typings (e.g. N3). Which has been installed via npm, thus:

npm install n3 --save

This, as is typical, is added to ./node_modules/n3/... and project.json. As mentioned the typings does not exist and needs to be added manually. I create an ./@types/n3.d.ts file for this purpose. For our purposes it is not particularly important what the definitions actually are but something like the following is a good start:

declare namespace N3 {
}

declare module "n3" {
    export = N3;
}

Now to your question. Update the 'tsconfig.json':

...
"compilerOptions": {
    "typeRoots": [
      "node_modules/@types",
      "@types"
    ],
...
"paths": {
  "*": [
    ...
    "./@types/*"
  ]

It will still be necessary to deal with the run-time resolution for locating the corresponding *.js files but that is a different question than the one you asked.

For reference you may find What is new in TypeScript and this discussion thread useful.

This approach works fine when working with global variables but not so much with modules.

Update the 'tsconfig.json':

...
"paths": {
  "*": [
    ...
    "./@types/*"
  ],
  "foo": [ "./@types/foo.d.ts" ]
  },
 ...