I am writing a nodeJS service that uses a bunch of npm modules without @types.
The tsc error message tells me that I need to add index.d.ts file, but it doesn't tell me where to put it. My helper.spec.ts file which also imports the same modules also cannot detect index.d.ts when run with jest
I put the file in my root along with tsconfig.json, but it doesn't detect it. My files and structure look like this:
Folder structure
node_modules
build
app.js
helper.js
another.js
spec
- helper.spec.ts
- another.spec.ts
src
- app.ts
- helper.ts
- another.ts
tsconfig.json
index.d.ts
jest.config.json
package.json
package-lock.json
tsconfig.json
{
"compilerOptions": {
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"allowJs": true, /* Allow javascript files to be compiled. */
"outDir": "build", /* Redirect output structure to the directory. */
"strict": true, /* Enable all strict type-checking options. */
},
"include": [
"src/**/*.ts",
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
index.d.ts
declare module "module-one";
declare module "module-two";
declare module "module-three";
package.json
{
"dependencies": {
"module-one": "^2.0.4",
"module-two": "^1.3.3",
"module-three": "0.0.3",
"@types/lodash": "^4.14.129",
},
"devDependencies": {
"@types/jest": "^24.0.13",
"@types/node": "^9.6.0",
"cpx": "^1.5.0",
"jest": "^24.8.0",
"ts-jest": "^24.0.2",
"typescript": "^3.4.5"
},
"scripts": {
"start": "cd build && node app.js",
"test": "jest",
"build": "tsc",
"postinstall": "npm run-script build"
},
}
Where does tsc and jest expect the index.d.ts?
Some articles that suggested to create one index.d.ts for each module e.g. ./types/module-one/index.d.ts
, ./types/module-two/index.d.ts
, ./types/module-three/index.d.ts
and then edit tsconfig.json compilerOptions.typeRoots
to include ./types
folder.
But I want to just have 1 index.d.ts with all the declarations.
When I edit tsconfig.json include
to include index.d.ts
file, I find that tsc can compile the files in my src folder. However when I run jest, it is still complaining that my module index.d.ts is missing.
EDIT: If I remove my tsconfig.json, then jest will run correctly without complaining about missing module, but then I cannot tsc build my src files.
If I keep the tsconfig.json, then tsc will build my src files, but jest will complain that module-one is undefined.
EDIT 2:
I found that if I set [jest.config.ts].globals.ts-jest.diagnostics = false
, then the error goes away and all my test pass! But I don't think that is the correct fix?
For future people: check out the TypeScript doc: typescriptlang.org/docs/handbook/declaration-files/templates/… The "d.ts" file is used to provide typescript type information about an API that's written in JavaScript. The idea is that you're using something like jQuery or underscore, an existing javascript library.
Where do you put custom d.ts files if you're making custom ones for your project? When a TypeScript script gets compiled there is an option to generate a declaration file (with the extension .d.ts) that functions as an interface to the components in the compiled JavaScript.
You can create your initial .d.ts files using tsc -allowJs main.js -d then edit them as required manually to improve the type checking and documentation. In most cases the implementation and interface have the same name, here mashString. But you can have alternative implementations.
d stands for declaration files: When a TypeScript script gets compiled there is an option to generate a declaration file (with the extension .d.ts) that functions as an interface to the components in the compiled JavaScript.
TLDR: for some undecipherable for normal human being reason, TypeScript looks for index.d.ts in a directory pointed to by baseUrl compiler option!
The idiotic-but-correct answer is "You are to put your index.d.ts in place where you transpiler will find it"
Well, not THAT idiotic. Just remember that copypasting half of the config from one working project and half from other will most likely give you the non-working config.
According to this article, I've added to my tsconfig.json
{
"compilerOptions": {
"typeRoots": [ "./types", "./node_modules/@types"],
...
},
...
}
whoops, nothing happened.
Most likely, because "Additionally, this article assumes you are using TypeScript 2.x." - and I'm using 3.x.
Dumb copypasting never works properly.
Using truss (strace counterpart for FreeBSD), I've found that transpiler ignores my typeRoots completely. It searched for my index.d.ts in /node_modules/@types/vue-native-notification/index.d.ts - in my src directory, in my project directory, home and so far up to /node_modules/@types/vue-native-notification/index.d.ts
Okay, symlinking my src/types/vue-native-notification to node_modules/@types/vue-native-notification did the trick, but it was not the thing I want. I don't want to patch my tree according to transpiler's default preferences!
According to official docs, the typesRoot option was renamed to types. Very microsoftish.
Okay, I've changed typesRoot to types.
Now I cant trace transpiler reading src/types/vue-native-notification/index.d.ts ... and throws out the same error!
I've wrote some words into index.d.ts and found that it does not get compiled. Strange indeed.
Without a trace of hope, I've tried seemingly meaningless idea of setting a baseUrl, but it helped. Removal of types compiler option did not change a thing.
I'm totally dissatisfied with the success, it looks pretty magic. But it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With