Ts-node: Help! My Types Are Missing! (tsc vs ts-node disparity)

Created on 13 Aug 2019  Â·  4Comments  Â·  Source: TypeStrong/ts-node

Using node v11.12.0 and ts-node v8.3.0, I get different behaviour between tsc running inside a langauge server in vscode 3.5.2 (node_modules has 3.5.3) for extended interfaces, when running with node -r ts-node/register.

The full command line is: TS_NODE_PROJECT=tsconfig.server.json node --inspect=9229 -r ts-node/register server/index.ts.

tsconfig.json has contents:

{
  "compilerOptions": {
    "allowJs": true,
    "downlevelIteration": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "noUnusedLocals": false,
    "noUnusedParameters": true,
    "preserveConstEnums": true,
    "removeComments": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "strictNullChecks": true,
    "target": "es2020",
    "typeRoots": [
      "./node_modules/@types",
      "./types"
    ]
  },
  "exclude": [
    "node_modules",
    "cypress",
    "dist",
    "next.config.js"
  ],
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ]
}

and tsconfig.server.json:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "dist",
    "target": "es2017",
    "isolatedModules": false,
    "noEmit": false
  }
}

does not apply, but causes an error. Folder structure;

$ tree types
types
├── custom.d.ts
├── dom.d.ts
├── express
│   └── index.d.ts

Contents of index.d.ts:

declare module 'http' {
  export interface IncomingMessage {
    logger: import('../../lib/logary/logger').SpanLogger;
  }
}

Error:

[nodemon] starting `node -r ts-node/register server/index.ts`

site/node_modules/ts-node/src/index.ts:245
    return new TSError(diagnosticText, diagnosticCodes)
           ^
TSError: ⨯ Unable to compile TypeScript:
server/idp/login.ts:18:9 - error TS2339: Property 'logger' does not exist on type 'Request'.

18     req.logger.info("GET /accounts/login Missing `login_challenge` param")
           ~~~~~~

    at createTSError (site/node_modules/ts-node/src/index.ts:245:12)
    at reportTSError (site/node_modules/ts-node/src/index.ts:249:19)
    at getOutput (site/node_modules/ts-node/src/index.ts:362:34)
    at Object.compile (site/node_modules/ts-node/src/index.ts:395:32)
    at Module.m._compile (site/node_modules/ts-node/src/index.ts:473:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:810:10)
    at Object.require.extensions.(anonymous function) [as .ts] (site/node_modules/ts-node/src/index.ts:476:12)
    at Module.load (internal/modules/cjs/loader.js:666:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:606:12)
    at Function.Module._load (internal/modules/cjs/loader.js:598:3)

workaround that makes it work:

/// <reference types="../../types/express" />
/// <reference types="../../node_modules/@types/express" />

This means that ts-node when used via ts-node/register does not load the typescript definitions from the configured folders.

This issue has a long discussion showing approximately the same:

https://github.com/TypeStrong/ts-node/issues/782#issuecomment-496685993

Yes, I have read the docs, both the handbook and the readme about types; hence the pun in the title of this issue. I think it's an issue since ts-node and the ts lang server diverge.

Most helpful comment

Looking back now that you've told me the solution; for a few different reasons;

  • ts-node/register is only documented deep down in a comment thread accessible by searching for it and then it's only with a single sentence akin to "try this", so there's no documentation specifying the invariants I can expect to rely on when using it
  • I read past --files in the docs multiple times during setting it up, but I'm not looking to specify multiple files, only the project file, which is what I am setting with TS_NODE_PROJECT; however, I now know that I also have to encourage it with TS_NODE_FILES=true.
  • TS_NODE_FILES also confused me with the "files"-property in tsconfig.json
  • I expected me configuring tsconfig.json to use typeRoots and then telling ts-node to use tsconfig.json to mean that it did use (all of) tsconfig.json.
  • What is ignored and what is not ignored from tsconfig.json by default for ts-node is undocumented.

On the files flag and files file array; suggestion — it's not really the "files" I want to compile that we're talking about here, so you could still start by only looking at the entrypoint file and then when type resolution is needed for non-local (to the entrypoint) types, load the typeRoots' files.

About compilation latency; it's irrelevant for me since nextjs is the second thing that starts, and I presume that starts a second typescript compiler all on its own inside the express process, and that means I have to wait for it to fully type-check every file in my project anyway. That's where I have latency (about 40 seconds of it) that I would like to reduce, if any.

All 4 comments

Why don't you just run it with --files? The reason it's this way by default is because there are just as many people complaining about performance, which deferring loading everything within a project for a file or two is an easy win.

Looking back now that you've told me the solution; for a few different reasons;

  • ts-node/register is only documented deep down in a comment thread accessible by searching for it and then it's only with a single sentence akin to "try this", so there's no documentation specifying the invariants I can expect to rely on when using it
  • I read past --files in the docs multiple times during setting it up, but I'm not looking to specify multiple files, only the project file, which is what I am setting with TS_NODE_PROJECT; however, I now know that I also have to encourage it with TS_NODE_FILES=true.
  • TS_NODE_FILES also confused me with the "files"-property in tsconfig.json
  • I expected me configuring tsconfig.json to use typeRoots and then telling ts-node to use tsconfig.json to mean that it did use (all of) tsconfig.json.
  • What is ignored and what is not ignored from tsconfig.json by default for ts-node is undocumented.

On the files flag and files file array; suggestion — it's not really the "files" I want to compile that we're talking about here, so you could still start by only looking at the entrypoint file and then when type resolution is needed for non-local (to the entrypoint) types, load the typeRoots' files.

About compilation latency; it's irrelevant for me since nextjs is the second thing that starts, and I presume that starts a second typescript compiler all on its own inside the express process, and that means I have to wait for it to fully type-check every file in my project anyway. That's where I have latency (about 40 seconds of it) that I would like to reduce, if any.

I expected me configuring tsconfig.json to use typeRoots and then telling ts-node to use tsconfig.json to mean that it did use (all of) tsconfig.json.

It does and did, I think the configuration of typeRoots is incorrect. TypeScript only found the first one. If you had named it express-logging-extension or something this would be a non-issue.

so you could still start by only looking at the entrypoint file and then when type resolution is needed for non-local (to the entrypoint) types, load the typeRoots' files.

Yes, this is how it works today. Except all these details are within TypeScript and not ts-node.

About compilation latency; it's irrelevant for me since nextjs is the second thing that starts, and I presume that starts a second typescript compiler all on its own inside the express process, and that means I have to wait for it to fully type-check every file in my project anyway.

Wouldn't this imply that running two compilers would actually run at 2x 40s?

The reason I offered --files as a solution originally is specifically because you commented on the tsc vs ts-node disparity FWIW. The typeRoots gotcha is something I wouldn't have noticed if I hadn't debugged this once before for someone else :frowning:

Was this page helpful?
0 / 5 - 0 ratings