11

OK so I have an interesting situation in setting up my Node.js TypeScript project. I want to be able to refer to my local modules using a non-relative require reference. The way TypeScript and Node.js look up modules is to look for a node_modules directory in the current directory and then each parent directory until they find such a directory containing the reference. So let's say I have a module I want to reference in the following directory structure:

/node_modules        <-- Main NPM modules dir
    /...
/package.json
/src
    /node_modules    <-- My local modules dir
        /modules
            /myModule.ts
    /scripts
        /init.ts

... and in init.ts I reference myModule like this:

import myModule from "modules/myModule";

As I understand it, I want TypeScript to transpile my node_modules directory over to the output dist directory along with all my other .ts file directories, so that the dist directory looks like this:

/node_modules        <-- Main NPM modules dir
    /...
/package.json
/dist
    /node_modules    <-- My local modules dir
        /modules
            /myModule.js
    /scripts
        /init.js

Then, when Node.js looks for the module it will find it at dist/node_modules/modules/myModule.js. So in this case I actually do want TypeScript to include the node_modules directory in its input files. I seem to be missing something fundamental, though, because TypeScript actually ignores this directory by default.

Is my scenario a legitimate one for including the node_modules directory, and if so, how can I make TypeScript include it in the transpilation when I just run tsc (and therefore it will use my tsconfig.json file)?

UPDATE: I have found that I can make it include my node_modules directory by explicitly putting it in the include directive in the .tsconfig.json like so:

"include": [
    "./src/node_modules/**/*",
    "./src/**/*"
]

The question remains; am I getting something fundamentally wrong here, because I am having to override something TypeScript excludes by default? I've tested this and when I make it transpile node_modules, it does indeed find my local modules correctly.

Jez
  • 27,951
  • 32
  • 136
  • 233
  • I believe there is a way for TS to alias non-relative module specifiers to relative paths. You might try that instead of the whole node_modules business – PitaJ Oct 02 '17 at 00:40
  • @PitaJ Care to elaborate on how it does that? – Jez Oct 02 '17 at 08:27
  • I'm also wondering the same thing. A quick look at this [repo](https://github.com/Microsoft/TypeScript-Node-Starter), I would think that the dist files use the same node_modules as the dev files. If so, that doesn't look so right. Anyway I haven't gone deep into it because I don't have mongodb installed. Once I do, I'll come back and let you know – paibamboo Oct 02 '17 at 08:59
  • @paibamboo The point is that that repo doesn't define *any* of its own local ES6 modules - everything is directly in the `.ts` files, and all includes are NPM modules. So it doesn't provide any example of defining your own ES6 modules, which are basically just a `.js` file with an `export` statement. – Jez Oct 02 '17 at 14:40
  • I thought your question was how to properly compile myModule.ts when your init.ts imports it without including in tsconfig it explicitly. You never mentions about ES6 modules in the question. – paibamboo Oct 02 '17 at 14:56
  • I say "local modules" what did you think that meant? – Jez Oct 02 '17 at 15:04
  • Your example is myModule.ts. That's what I thought that meant. – paibamboo Oct 02 '17 at 15:38
  • Yes it does, and if `myModule.ts` has an `export` statement that makes it an ES6 module. – Jez Oct 02 '17 at 15:49
  • I've found an interesting way to deal with local modules is to just install them. You can run `npm install /path/to/some/module/folder`. I'm not sure exactly how it's handled under the hood, but when you make changes to the module, it reflects in the rest of your project. – skylize Oct 02 '17 at 20:04
  • @Jez I think you are getting confused. First you say that everything of that repo is "directly in .ts files" and you further mention about ES6 modules which are "basically just a .js file with an export statement". This is implying that this repo is not what you want. Later you state that "myModule.ts has an export statement that makes it an ES6 module". Now the logic is wrong. If the first statement is true, the second is false. If the second is true, the first is false. Think about it :) – paibamboo Oct 03 '17 at 15:58
  • Apart from that I still think that that repo is relevant. It doesn't matter if it's your own module or someone else module as long as it's in node_module folder. The point is whether it makes sense or not to include node_modules in your dist folder. As I've been searching an answer for a few days. My conclusion is you don't need to. Just do the same as that repo does. The files in dist folder can still find node_modules anyway. – paibamboo Oct 03 '17 at 16:03

1 Answers1

2

That's not correct to include node_modules for transpilation. Because node_modules contains javascript and doesn't requires second transpilation in case of ts libraries, they should have declarations in .d.ts.

If you have custom types, or you want to add types to some libraries that don't have them, you need to use own declarations or @types/* packages.

in your tsconfig.json you can define type roots (where to load declarations from).

{
    "compilerOptions": {
        "typeRoots": ["./declarations", "./node_modules/@types"],
        "types": ["node"],
    }
}

then you can install npm i --save-dev @types/node@^12 for example to get declarations of nodejs v12.

and define your own declarations in declarations for express for example: ./declarations/express/index.d.ts

import * as express from 'express';

declare module 'express' {
    export interface Request {
        user?: {
            id: string;
            name: string;
        }
    }
}
satanTime
  • 12,631
  • 1
  • 25
  • 73