ts-node: "error TS2304: Cannot find name" after updating to 7.0.0

I updated ts-node from 6.2.0 to 7.0.0 and I started to get the following error:

TSError: ⨯ Unable to compile TypeScript:
src/common/atlas/atlas.constants.ts(3,27): error TS2304: Cannot find name 'Tile'.
src/common/atlas/atlas.constants.ts(6,31): error TS2304: Cannot find name 'ITileLayer'.
src/common/atlas/atlas.constants.ts(27,28): error TS2304: Cannot find name 'ITileLayer'.

    at createTSError (/Users/miguel/src/later/node_modules/ts-node/src/index.ts:261:12)
    at getOutput (/Users/miguel/src/later/node_modules/ts-node/src/index.ts:367:40)
    at Object.compile (/Users/miguel/src/later/node_modules/ts-node/src/index.ts:557:11)
    at Module.m._compile (/Users/miguel/src/later/node_modules/ts-node/src/index.ts:439:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:713:10)
    at require.extensions.(anonymous function) (/Users/miguel/src/later/node_modules/ts-node/src/index.ts:442:12)
    at Object.nodeDevHook [as .ts] (/Users/miguel/src/later/node_modules/node-dev/lib/hook.js:61:7)
    at Module.load (internal/modules/cjs/loader.js:612:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
    at Function.Module._load (internal/modules/cjs/loader.js:543:3)
[ERROR] 11:14:48 TSError

It looks like this version is not able to find my custom type definitions. I recently started to learn typescript so I’m not sure if what I’m doing is good practice, this is my folder structure

image

Y put my types inside *.d.ts files and nothing more, this worked before updating.

Not sure if this can help but here is my .tsconfig

{
	"compilerOptions": {
		"strict": true,
		"alwaysStrict": true,
		"module": "commonjs",
		"moduleResolution": "node",
		"types": ["node", "jest", "pixi.js", "matter-js"],
		"newLine": "LF",
		"outDir": "lib",
		"jsx": "preserve",
		"target": "es2017",
		"lib": [
			"es2017",
			"dom"
		],
		"noUnusedLocals": true,
		"noUnusedParameters": true,
		"noImplicitAny": true,
		"noFallthroughCasesInSwitch": true,
		"experimentalDecorators": true,
		"baseUrl": "./src",
		"paths": {
			"common/*": [
				"./common/*"
			],
			"client/*": [
				"./client/*"
			],
			"server/*": [
				"./server/*"
			]
		}
	},
	"include": [
		"src/common/**/*.ts",
		"src/client/**/*.ts"
	],
	"exclude": [
		".git",
		"node_modules"
	]
}

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 3
  • Comments: 41 (23 by maintainers)

Commits related to this issue

Most upvoted comments

Why make a major release so quickly? I do agree that, as @weswigham says, “the build orchestrator is not part of the build it orchestrates”, but the fix is kind of on the extreme side. Why not at least try taking some useful parts out of the tsconfig.json, if there is one? esModuleInterop, lib, typeRoots, exclude, the strictness settings, etc.

Sticking to v6 for now, since I don’t want to:

  • Maintain a separate tsconfig.json just for ts-node.
  • Augment every single ts-node invocation with a --project.
  • Use triple-slash pragmas where I previously didn’t have to.

It’s possible that I’m in the tiny minority here, but the discussion was way too short for this change, IMO.

@blakeembrey Thank you for taking time to look into this. Decided to investigate this myself, and wow, still got some misconceptions. Everything was working, so I was sure I had it all figured out…

Indeed, typeRoots was doing nothing. The typings were being picked up by TypeScript’s default include (my tsconfig.json has only an exclude). It would work if the typings did have the right shape, but typeRoots is for global declarations, paths is a better fit for that. Which is conveniently omitted in tsconfig.json docs, and is instead described in module resolutions docs.

The “fix” is to put this in place of typeRoots:

"baseUrl": ".",
"paths": { "*" : ["typings/*"] }

And translate all typings from typings/*.d.ts to typings/*/index.d.ts, i.e. from this:

// typings/some-npm-package.d.ts
declare module "some-npm-package" {
  const x: string;
  export = x;
}

To this:

// typings/some-npm-package/index.d.ts
declare const x: string;
export = x;

I’m choosing this approach because I always wanted my typings to look the same as what you would find on DefinitelyTyped, and now it’s possible, and it works with both ts-node and tsc.

I also have typings like this:

// typings/svg.d.ts
declare module "*.svg" {
  const x: string;
  export default x;
}

These are okay to leave as-is, since they make sense only in the context of a bundler like Webpack, and ts-node shouldn’t be able to execute files which import SVGs and such. One exception is JSON, but there’s a setting for it now in TS 2.9. This way, there’s no need in involving typeRoots at all.

I’m glad this change broke my stuff, now I have a better config and a better understanding of it, thanks.

Edit

Have fiddled around some more, and found out that paths works with declare module 'some-npm-package' too, so if you’re in a rush, you don’t even have to do the translation part, just make sure the directory matches the module.

Adding typings/*/index.d.ts to exclude can help with some typos/mistakes.

A major version means breaking changes. If something breaks, you can check the changelog or commits to see what happened. See https://github.com/TypeStrong/ts-node/releases/tag/v7.0.0 and the notice in the README. If they aren’t clear, feel free to clarify them. If you’d like the old behaviour for now, you can use ts-node --files.

Edit: Reference to issue which prompted changing the behaviour - https://github.com/js-cli/js-interpret/pull/51.

@weswigham Would you be kind enough to share the recommended way someone should include these files into their ts-node project (without --files)?

For the lazy webpack users that are running into this issue:

Assuming the following…

  1. You don’t feel like refactoring.
  2. You are starting webpack using an npm script like this…
{
  "scripts": {
    "start": "webpack"
  }
}

Simply change it to this and it’ll work like before:

{
  "scripts": {
    "start": "TS_NODE_FILES=true webpack"
  }
}

@19majkel94 There’s documentation and links in this thread pointing out what you’ve run into. You need to make it a directory and use index.d.ts.

What about ambient module declaration for module augmentation?

declare namespace NodeJS {
  interface Global {
    TypeGraphQLMetadataStorage: import("../metadata/metadata-storage").MetadataStorage;
  }
}

I’ve tried the typeRoots and paths tricks but no success 😞

@salemdar Maybe I missed something but I do not see any way to get gulp to just pick up an additional files flag to pass to ts-node. The workaround I use is:

  1. Move gulpfile.ts to a different name. Note that this is still a TypeScript file. It is just no longer named gulpfile.ts.

  2. Write a gulpfile.js that initializes ts-node as I wish and then loads my renamed gulpfile.ts.

This is what I’m using for the gulpfile.js:

"use strict";

require("ts-node").register({
  transpileOnly: true,
});

require("./gulptasks/main"); // Load the renamed gulpfile.ts

I’ve decided to go with transpileOnly: true to fix my problem. I figured that there was no benefit to having ts-node check types during a Gulp run. I already have an IDE that does type checking on the fly, which catches most problems (and I expect any collaborator to have something equivalent to my setup), and I have a tslint task that includes type-checking, which would catch things I may not notice through the IDE.

If you do want Gulp to run type checking and use files then you can just replace transpileOnly: true, with files: true. I’ve tested both and they both worked around the compilation errors I got after upgrading to ts-node 7.0.0.

@blakeembrey Poor reading skills this time of day + didn’t look at the diff. Interpreted “Skip loading tsconfig.json files by default to speed up startup” as “tsconfig.json is ignored now”. Sorry.

What do you mean by “global” types? I have a few of these:

// typings/some-npm-package.d.ts
declare module "some-npm-package" {
  // ...
}

And typeRoots: [./typings] in the config. v6 sees them, v7 doesn’t.

Actually the way paths is used in my example has at least one drawback. For example webpack seems to be making require("crypto") calls and this yields thousands of disk lookups for crypto, crypto.js, crypto.ts etc in the two paths. I’m not sure what’s the performance impact, but I thought you guys should know.

Also now that I come to think about this once agan, is this test wrong? Shouldn’t it be expect(err).not.to.match(/Error: Cannot find module 'does-not-exist'/), because the typings do exist?

EDIT: After initial testing, my build time was reduced from ~120 seconds to ~75 seconds after I removed the * path and moved the types to node_modules/@types, so the performance impact seems to be huge.

They’re global. I didn’t even try typeRoots, because of a previous bad experience from misunderstanding them and @jeremejevs was so convincing, that I decided to try his solution first. If I specify typeRoots: ["./typings", "./node_modules/@types"], will it include types from eg. ./node_modules/@material-ui/core/index.d.ts, if I import a module from @material-ui/core? (I cannot test it at the moment.)

I really feel like there should be more context in the release notes for a major version.