ts-node: Custom typings not working with ts-node 8.0.2

After updating to ts-node version 8.0.2 the custom typings (currently placed in ./types) don’t work anymore. When I am changing the version to 8.0.1 the typings are working fine.

Typescript version: 3.3.3

Current tsconfig.json:

{
  "compilerOptions": {
    "sourceMap": true, // allow sourcemap support
    "strictNullChecks": true, // enable strict null checks as a best practice
    "strict": true,
    "target": "esnext", // specify ECMAScript target version
    "module": "commonjs",
    "moduleResolution": "node",
    "noImplicitAny": true,
    "declaration": false,
    "typeRoots": ["./@types"],
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "outDir": "./build"
  },
  "include": ["./src/", "./types"],
  "exclude": ["node_modules", ".logs", "upload"]
}

Error Message:

uncaughtException: ⨯ Unable to compile TypeScript:
src/import/law.ts(2,28): error TS7016: Could not find a declaration file for module 'csv-string'. '/home/patrick/dev/bodner-api/node_modules/csv-string/index.js' implicitly has an 'any' type.
  Try `npm install @types/csv-string` if it exists or add a new declaration (.d.ts) file containing `declare module 'csv-string';`

TSError: ⨯ Unable to compile TypeScript:
src/import/law.ts(2,28): error TS7016: Could not find a declaration file for module 'csv-string'. '/home/patrick/dev/bodner-api/node_modules/csv-string/index.js' implicitly has an 'any' type.
  Try `npm install @types/csv-string` if it exists or add a new declaration (.d.ts) file containing `declare module 'csv-string';`

    at createTSError (/home/patrick/dev/bodner-api/node_modules/ts-node/src/index.ts:228:12)
    at getOutput (/home/patrick/dev/bodner-api/node_modules/ts-node/src/index.ts:334:40)
    at Object.compile (/home/patrick/dev/bodner-api/node_modules/ts-node/src/index.ts:367:11)
    at Module.m._compile (/home/patrick/dev/bodner-api/node_modules/ts-node/src/index.ts:413:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/home/patrick/dev/bodner-api/node_modules/ts-node/src/index.ts:416:12)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 8
  • Comments: 42 (9 by maintainers)

Commits related to this issue

Most upvoted comments

When using with ts-node you have to add --files flag

ts-node --files src/server.ts 

I had the same issue. Turns out you need to use ts-node --files app.ts instead of ts-node app.ts.

folder structure

<project_root>/
-- tsconfig.json
-- src/
  -- types
    -- global
       -- index.d.ts

tsconfig.json

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

This works for me. and index.d.ts’s name must be index.

I am having this exact same issue and nothing mentioned here works. I am on 8.3.0

/// <reference types="./types/untyped_js_lib" /> was the solution that finally worked for me.

In my case, I was trying to use an express.d.ts file but following 3dmard’s example (https://github.com/3mard/ts-node-example) solved the issue.

Here is an example for Express.Request

  1. Create a file located at typings/express/index.d.ts :
declare namespace Express {
    export interface Request {
        token: string;
    }
}
  1. Add the typeRoots entry in the tsconfig.json, with the right order :
{
    "compilerOptions": {
        "typeRoots": ["./typings", "./node_modules/@types"],
    }
}

I added a file ./typings/express/index.d.ts with the following code:

import { User } from '../../modules/users/models/user'

declare global {
  namespace Express {
    export interface Request {
      user?: User;
    }
  }
}

It was not working, until i inverted type typings and node_modules/@types, it ended like this:

"typeRoots": ["./src/typings", "./node_modules/@types"],

@blakeembrey I’ve tried both with and without typeRoots at all and got the same result.

Feel free to submit a PR improving documentation.

To submit a PR, one should have an understanding about what they’re doing. I just don’t get what this option does, that’s why I’m asking here.

Then why are typeRoots referenced as solution to missing types in https://github.com/TypeStrong/ts-node#help-my-types-are-missing? It’s just seems unlogical.

Your typeRoots probably aren’t configured properly if it doesn’t work.

Feel free to submit a PR improving documentation.

@VictorioBerra possibly:

<project_root>/
-- tsconfig.json
-- typings/
  -- @ABC/
    --modules123/
       -- index.d.ts

The above solution worked for me, having this exact folder structure with my global types in a ‘typings’ folder

For people who open this issue based on not working typeRoots in VSCode debugger.
Take a look at my launch.json config file. To say ts-node to load files from typeRoots you need to add:

      "env": {
        "TS_NODE_FILES": "true",
        "TS_NODE_PROJECT": "./tsconfig.json"
      },

It works for me image

When using with ts-node you have to add --files flag

ts-node --files src/server.ts 

this still works for me in 2021… and i do not understand why this is not default behavior

To help anyone who is just looking for something else to try here is what worked for me when trying to extend ExpressJS’ Request. I had to have tried more than a dozen things before getting this to work:

  • Flip the order of what everyone is recommending in the “typeRoots” of your tsconfig.json (and don’t forget to drop the src pathing if you have a rootDir setting in tsconfig such as “./src”). Example:
"typeRoots": [
      "./node_modules/@types",
      "./your-custom-types-dir"
]
  • Example of custom extension ('./your-custom-types-dir/express/index.d.ts"). I had to use inline import and default exports to use classes as a type in my experience so that is shown too:
declare global {
  namespace Express {
    interface Request {
      customBasicProperty: string,
      customClassProperty: import("../path/to/CustomClass").default;
    }
  }
}
  • Update your nodemon.json file to add the “–files” command to ts-node, example:
{
  "restartable": "rs",
  "ignore": [".git", "node_modules/**/node_modules"],
  "verbose": true,
  "exec": "ts-node --files",
  "watch": ["src/"],
  "env": {
    "NODE_ENV": "development"
  },
  "ext": "js,json,ts"
}

@evenfrost It seems that omitting --files make the compiler ignore files and include of tsconfig.json

https://github.com/TypeStrong/ts-node/blob/master/src/index.ts#L644

@zerubeus’s comment helped me and fixed missing declarations error, thank you. But what exactly are --files flag? Readme doesn’t actually help, or it’s just me who doesn’t get it.

Load files from tsconfig.json on startup

Which files does it load? I don’t have files property in my tsconfig.json, so how is it referred to each other? I have typeRoots in my tsconfig.json, but ts-node doesn’t seem to tolerate it at all until you provide --files flag. Then why are typeRoots referenced as solution to missing types in https://github.com/TypeStrong/ts-node#help-my-types-are-missing? It’s just seems unlogical.

@kgaregin here is an example of extending express request https://github.com/3mard/ts-node-example

When using with ts-node you have to add --files flag

ts-node --files src/server.ts 

God! It works for me. Thanks to share its solution.

Updating tsconfig.json like this works for me now:

{
  "compilerOptions": {
    "sourceMap": true, // allow sourcemap support
    "strictNullChecks": true, // enable strict null checks as a best practice
    "strict": true,
    "target": "esnext", // specify ECMAScript target version
    "module": "commonjs",
    "moduleResolution": "node",
    "noImplicitAny": true,
    "declaration": false,
    "typeRoots": ["./node_modules/@types", "./typings"],
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "outDir": "./build"
  },
  "include": ["./src/", "./typings"],
  "exclude": ["node_modules", ".logs", "upload"]
}

Folder structure is as described in https://github.com/TypeStrong/ts-node#help-my-types-are-missing.

@kgaregin Your typeRoots should be only "./typings". Does that work now?

With nodemon in package.json

"scripts": {
    "start:dev": "nodemon -r dotenv/config --watch 'src/**/*.ts' --exec 'ts-node --files' src/server.ts",
  },

By default, ts-node does not load files, include or exclude from tsconfig.json on startup. The --files option enables it.

See https://github.com/TypeStrong/ts-node#missing-types

Try using a triple-slash directive to include the types. https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-types-

Keep in mind that tsc is effectively always using the --files flag.

Using ts-node 8.5.0, typescript 3.9.7, trying to add custom declaration file to @x/y package. typeRoots didn’t help:

Folders structure:

- root
    -- src
    -- types
        -- @x
           -- y
                -- index.d.ts
    -- tsconfig.json

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "./",
    "emitDecoratorMetadata": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "module": "commonjs",
    "outDir": "dist",
    "removeComments": true,
    "sourceMap": true,
    "strict": true,
    "target": "es6",
    "moduleResolution": "node",
    "paths": {
      "@models/*": [
        "src/models/*"
      ],
      "@shared/*": [
        "src/shared/*"
      ],
      "@server": [
        "src/Server"
      ]
    },
    "types": [
      "node"
    ],
    "typeRoots": [
      "types",
      "node_modules/@types"
    ]
  },
  "include": [
    "src/**/*.ts",
  ]
}

only the --files flag worked. Feels like the wrong solution to include all ts files using the --files flag to make it work.

“Triple-slash directives are only valid at the top of their containing file. A triple-slash directive can only be preceded by single or multi-line comments, including other triple-slash directives. If they are encountered following a statement or a declaration they are treated as regular single-line comments, and hold no special meaning.”

@evenfrost I found this from TypeScript official docs. I think it could answer your question.

If the “files” and “include” are both left unspecified, the compiler defaults to including all TypeScript (.ts, .d.ts and .tsx) files in the containing directory and subdirectories except those excluded using the “exclude” property.

looks like it works again with ts-node@8.0.3 version (like this “typeRoots”: [“./node_modules/@types”, “./typings”])