Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help! My Types Are Missing! (tsc vs ts-node disparity) #866

Closed
haf opened this issue Aug 13, 2019 · 4 comments
Closed

Help! My Types Are Missing! (tsc vs ts-node disparity) #866

haf opened this issue Aug 13, 2019 · 4 comments

Comments

@haf
Copy link

haf commented Aug 13, 2019

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:

#782 (comment)

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.

@blakeembrey
Copy link
Member

blakeembrey commented Aug 14, 2019

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.

@haf
Copy link
Author

haf commented Aug 14, 2019

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.

@blakeembrey
Copy link
Member

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?

@blakeembrey
Copy link
Member

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 😦

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants