TypeStrong / ts-node

TypeScript execution and REPL for node.js
https://typestrong.org/ts-node
MIT License
12.91k stars 534 forks source link

Cannot find module defs using typeRoots #682

Closed shusson closed 6 years ago

shusson commented 6 years ago

If you have a config like this:

{
  "compilerOptions": {
    ...
    "typeRoots" : ["./typings"]
  }

And a directory structure like this:

-- tsconfig.json
  -- typings
    -- index.d.ts

ts-node will not be able to find the module defs in index.d.ts

ts-node will work if you have something like:

-- tsconfig.json
  -- typings
    -- <library_name>
      -- index.d.ts

Typescript will work with either setup.

blakeembrey commented 6 years ago

See the README. This is not the correct structure. It most likely works with TypeScript because you have it explicitly or explicitly in your includes.

shusson commented 6 years ago

Ok @blakeembrey , but then ts-node should have worked with with the --files flag right?

blakeembrey commented 6 years ago

Yes, probably. In any case this is based on the TypeScript compiler API, so I’d need a full reproduction if you believe it’s a bug.

shusson commented 6 years ago

Sorry my mistake. I couldn't reproduce with a simple setup. Looks like it's to do with our own structure.

MicahZoltu commented 6 years ago

I'm running into this problem after upgrading to ts-node 7.x and typescript 3.x. Everything was working with ts-node 6.x and typescript 2.7.x.

Did you ever figure out your issue?

Note: my tsconfig.json doesn't have any include/excludes and npx tsc works correctly. The problem is specific to when running npx ts-node myscript.ts.

Note2: This is a common ask in the issues here, but unlike most of them, me and the OP are following the instructions in the README and adding "typeRoots": [ "./typings" ] where our custom module definitions are defined. However, this doesn't appear to actually work.

MicahZoltu commented 6 years ago

See the README. This is not the correct structure.

Can you provide some details on why this is not the correct structure? It is accepted by TypeScript compiler without problem. There are two supported (as far as I know) ways to have modules. One is by creating some .d.ts file in typeRoots directory (e.g., my.d.ts) with one or more declare module 'whatever' { ... } blocks in it, and another is to create a a folder named myModule with a file named index.d.ts in it that contains declare module 'myModule' { ... }. Both methods appear to be fully supported by the compiler, but only the latter method appears to be supported by ts-node.

At the least, the README should be updated to mention that you cannot use the former style, and ideally a brief blurb or link to the reasoning would be appreciated.

blakeembrey commented 6 years ago

@MicahZoltu This is in the README. Both styles are supported. Please read the section about types to understand why it’s not working for you.

blakeembrey commented 6 years ago

FWIW, the first method you describe is not supported by TypeScript. It’s working accidentally with tsc because your configuration includes it, not because TypeScript looks it up. This is in the README. Feel free to share your project/structure if you feel this is incorrect.

MicahZoltu commented 6 years ago

@blakeembrey Can you be more specific? I have read the README several times over and the only workaround I have been able to find is the one @shusson mentioned, which is to break my module declarations out into index.d.ts files in folders named after the module and add a typeRoots section.

My tsconfig.json does not have a reference to files, include or exclude, in fact it is quite small/simple:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es2015",
        "noImplicitAny": true,
        "allowJs": false,
        "noEmit": true,
        "strict": true,
        "lib": [ "es2018", ],
    }
}

The readme says:

TypeScript Node does not use files, include or exclude, by default.

Great, I am not using any of those compiler options so that doesn't apply to me.

It then goes on to say:

For global definitions, you can use typeRoots:

Great, I have some global module definitions so I can put them into typeRoots.

Unfortunately, this is where things fall apart, putting my module definitions into a file in typeRoots does not work as I expect.

I somewhat suspect (after reading the readme 3 more times while drafting this response) that the magic is in this statement:

A types package is a folder with a file called index.d.ts or a folder with a package.json that has a types field. -- TypeScript Handbook

If I'm interpreting that correctly, when combined with your insistence that "the answer is in the README", it is saying that the typeRoots mentioned previously only works if the types are setup as type package folders within the typeRoots directory?


Since I don't want to be yet another person who complains but offers no solutions, I would recommend rewording that section to be more clear. Looking through GitHub issues, there are about a dozen issues with people struggling with this same problem, which suggests to me that the way it is currently worded is not immediately apparent to the casual ts-node user.

Perhaps something like:

For global definitions, you can use the typeRoots compiler option. This requires that your type definitions be structured as type packages (not loose TypeScript definition files). More details on how this works can be found in the TypeScript Handbook. Example tsconfig.json:

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

Example project structure:

<projcet_root>/
-- tsconfig.json
-- typings/
  -- <module_name>/
    -- index.d.ts

Example module declaration file:

declare module '<module_name>' {
    // module definitions go here
}

It’s working accidentally with tsc because your configuration includes it, not because TypeScript looks it up.

What part of my configuration is causing this to happen? I have included my tsconfig.json, and in fact tsc works without the typeRoots section at all. Is there some other config you are referring to besides tsconfig.json? I'm just running tsc in the directory with the tsconfig.json file and it is successfully compiling, I am not passing in any additional compiler options or providing any files.

blakeembrey commented 6 years ago

Feel free to submit a PR for the documentation change. I’m on mobile so unable to link to the section correctly, but that’s the correct section. It works with TypeScript by default because, when you don’t specify the files/includes, it would be traversing your entire directory for TypeScript files. I’m not sure if the expectation here otherwise, since tsc appears to be compiling everything right?

MicahZoltu commented 6 years ago

Yes, tsc is compiling everything when run from the directory containing the tsconfig.json. IIUC, you are saying that this means that tsc will naturally find any types you have in any directory that is being compiled, and normally you would only need to include typeRoots if you want to pull type data from a directory that is outside the directory being compiled. However, since ts-node doesn't compile anything by default other than the referenced file (and things that file references) it won't find any type files automatically unless they are located on the import lookup path (such as in node_modules).

blakeembrey commented 6 years ago

Pretty much, yes. To TypeScript, the global declarations can be understood any time (the structure is usually more import with the module style declarations). But yeah, since we aren’t globing the entire directory it needs to follow the structure TypeScript supports. Fortunately this is TypeScript native suppport, so fixing for ts-node does not change behaviour on the compiler.

I’d love to see the documentation PR, it’s definitely an improvement over what I originally wrote!

MicahZoltu commented 6 years ago

PR to edit documentation to hopefully reduce the number of people that show up here in the issues with the same problem: https://github.com/TypeStrong/ts-node/pull/698

andidev commented 1 year ago

@blakeembrey did something change here? This does not work for us

image

We have to configure all modules in the paths instead

"paths": {
    "src/*": ["src/*"],
    "module_name": ["types/module_name"]
},

we use

"ts-node": "10.9.1",
"typescript": "4.8.2",
joematune commented 9 months ago

We have to configure all modules in the paths instead

"paths": {
    "module_name": ["types/module_name"]
},

Odd as it seems, this worked for me. Thanks @andidev. Note for others that both of the following structures work:

types/
├── module_name
│   └── index.d.ts
└── module_name.d.ts