Could not find a declaration file for module 'module-name'. '/path/to/module-name.js' implicitly has an 'any' type

I read how TypeScript module resolution works.

I have the following repository: @ts-stack/di. After compiling the directory structure is as follows:

├── dist
│   ├── annotations.d.ts
│   ├── annotations.js
│   ├── index.d.ts
│   ├── index.js
│   ├── injector.d.ts
│   ├── injector.js
│   ├── profiler.d.ts
│   ├── profiler.js
│   ├── providers.d.ts
│   ├── providers.js
│   ├── util.d.ts
│   └── util.js
├── LICENSE
├── package.json
├── README.md
├── src
│   ├── annotations.ts
│   ├── index.ts
│   ├── injector.ts
│   ├── profiler.ts
│   ├── providers.ts
│   └── util.ts
└── tsconfig.json

In my package.json I wrote "main": "dist/index.js".

In Node.js everything works fine, but TypeScript:

import {Injector} from '@ts-stack/di';

Could not find a declaration file for module '@ts-stack/di'. '/path/to/node_modules/@ts-stack/di/dist/index.js' implicitly has an 'any' type.

And yet, if I import as follows, then everything works:

import {Injector} from '/path/to/node_modules/@ts-stack/di/dist/index.js';

What am I doing wrong?


Solution 1:

Here are two other solutions

When a module is not yours - try to install types from @types:

npm install -D @types/module-name

If the above install errors - try changing import statements to require:

// import * as yourModuleName from 'module-name';
const yourModuleName = require('module-name');

Solution 2:

If you're importing a third-party module 'foo' that doesn't provide any typings, either in the library itself, or in the @types/foo package (generated from the DefinitelyTyped repository), then you can make this error go away by declaring the module in a file with a .d.ts extension. TypeScript looks for .d.ts files in the same places that it will look for normal .ts files: as specified under "files", "include", and "exclude" in the tsconfig.json.

// foo.d.ts
declare module 'foo';

Then when you import foo it'll just be typed as any.


Alternatively, if you want to roll your own typings you can do that too:

// foo.d.ts
declare module 'foo' {
    export function getRandomNumber(): number
} 

Then this will compile correctly:

import { getRandomNumber } from 'foo';
const x = getRandomNumber(); // x is inferred as number

You don't have to provide full typings for the module, just enough for the bits that you're actually using (and want proper typings for), so it's particularly easy to do if you're using a fairly small amount of API.


On the other hand, if you don't care about the typings of external libraries and want all libraries without typings to be imported as any, you can add this to a file with a .d.ts extension:

declare module '*';

The benefit (and downside) of this is that you can import absolutely anything and TS will compile.