TypeScript: Error when importing untyped JS modules

TypeScript Version: 2.2.1

Steps

  1. In a simple TS project in VSCode, add "adal-node": "^0.1.22", to package.json and run npm install. This is a JS library with no types.
  2. Import the library in your index.ts as below

Code

import adal from "adal-node";

Expected behavior: Per this bug’s resolution #3019 this code should compile with no errors

Actual behavior: tsc.exe: ‘Could not find a declaration file for module ‘adal-node’. ‘e:/proj/node_modules/adal-node/lib/adal.js’ implicitly has an ‘any’ type.’

References: see #3019 and all its linked bugs

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 27
  • Comments: 46 (12 by maintainers)

Commits related to this issue

Most upvoted comments

@Spongman Actually, you can just have a global.d.ts at your project root with following content:

declare module '*';

It automatically makes all js modules any while ts modules keep working as intended.

Because you have turned on noImplicitAny. You need to get around it by doing declare module 'adal-node' (or declare module "*", I have yet to try this myself)

why does the noImplicitAny check fire when importing .js files? surely when you’re importing a .js file you’re explicitly declaring everything within it as any ?

it seems too heavy a burden to require everything to have a @types or for the user to create a .d.ts file just for this check not to fire.

this IMHO really kills Anders’ claim of ‘drop-in replacement’ for javascript.

It is still impossible to import untyped Javascript modules.

I’ve spent the past few hours trying to figure out how to use adapter.js with Typescript, and I’ve run into no end of problems. At this point, I’m ready to give up again on Typescript.

I’ve saved adapter.js in the src/ directory, along with main.ts. Things I’ve tried that haven’t worked:

import * as webrtc from 'adapter.js';

7:25 Cannot find module ‘adapter.js’.

import * as webrtc from 'adapter';

7:25 Cannot find module ‘adapter’.

declare module 'adapter.js';

5:16 Invalid module name in augmentation, module ‘adapter.js’ cannot be found.

declare module 'adapter.js';

5:16 Invalid module name in augmentation, module ‘adapter’ cannot be found.

import * as webrtc from './adapter.js';

7:25 Could not find a declaration file for module ‘./adapter.js’. ‘PROJECT/src/adapter.js’ implicitly has an ‘any’ type.

declare module './adapter.js';
import * as webrtc from './adapter.js';

ERROR in PROJECT/src/main.ts 5:16 Invalid module name in augmentation. Module ‘./adapter.js’ resolves to an untyped module at ERROR in PROJECT/src/main.ts 6:25 Could not find a declaration file for module ‘./adapter.js’. ‘PROJECT/src/adapter.js’ implicitly has an ‘any’ type.

// adapter.d.ts
declare module "adapter" {
    var _temp: any;
    export = _temp;  
}

// main.ts
declare module './adapter.js';
import * as webrtc from './adapter.js';

5:16 File ‘PROJECT/src/adapter.d.ts’ is not a module. 6:25 File ‘PROJECT/src/adapter.d.ts’ is not a module.

import adapter = require("./adapter.js");

5:1 Import assignment cannot be used when targeting ECMAScript modules. Consider using ‘import * as ns from “mod”’, ‘import {a} from “mod”’, ‘import d from “mod”’, or another module format instead.

Is there any way to do something simple like import * as BabiliPlugin from "babili-webpack-plugin"; with noImplicitAny enabled without getting warning TS7016 (“could not find a declaration file…implicitly has an ‘any’ type”)?

Typescript should act smarter in these cases. WHY ON EARTH we need to define a type definition if we explicitly import a JS module.

Hello! Could you please clarify where do I put this declaration file:

declare module 'adal-node';

And how do I instruct compiler to actually use it?

This should be behind another config flag or another frictionless solution, using noImplicitAny is best practice for TS, but creating a d.ts file and filling it with empty module declarations is just annoying.

This is still a JS world and we’re just trying to exist in it. I never had a manually created d.ts file (only auto-generated) and now it seems like a new requirement.

I’ve been hunting around for this answer for the better part of a month now. I found a solution that works in VS Code that isn’t a wholesale disabling of all validation for javascript/typescript and also did not require that I add files/declarations to a repository that is not mine.

Add one or both of these lines to your user settings:

"typescript.suggestionActions.enabled": false,
"javascript.suggestionActions.enabled": false,

Unlike "javascript.validate.enable": false (which you should not use), the above setting will remove those annoying [ts] Could not find a declaration file for module errors for untyped module imports and it will still play nice with linters and give you appropriate and relevant errors.

oops! you’re right that I have noImplicitAny compiler option set in my tsconfig.json. Totally forgot about it as its one of my default configs to writing TS.

I think I can work with the solution you posted on the other thread. Thanks for the quick feedback ! Appreciate it.

@mhegazy : I’m still not sure how to correctly use this declare module and import syntax to import untyped JS modules. Could you please provide a small snippet demonstrating how to accomplish that? Thanks.

Is there any way to do something simple like import * as BabiliPlugin from “babili-webpack-plugin”; with noImplicitAny enabled without getting warning TS7016 (“could not find a declaration file…implicitly has an ‘any’ type”)?

Add a declaration for your module, e.g.:

declare module "babili-webpack-plugin" {
     export ...
}

or simply:

declare module "babili-webpack-plugin";

@SCLeoX OMG THANK YOU. Hours of pounding my head against outdated docs and absolutely terrible error messages from tsc. If this simple workaround was the front page of http://www.typescriptlang.org then typescript adoption would double and it would also be the most useful thing on that website.

The issue as described by the OP seems fixed.

The other issue described in https://github.com/Microsoft/TypeScript/issues/15031#issuecomment-292011200, is because a module declaration (i.e declare module 'adal-node' {... }) inside another module (i.e. a file with at least one top-level import or export) is considered an “augmentation”. What you want is to move this declaration to a global .d.ts (as you want it to be in the global scope) file instead of keeping it in your module.

I can confirm @SCLeoX’s suggestion. I just created a root-level global.d.ts file for untyped 3rd party libs. IMO, * is a bit too heavy-handed and I’d rather be explicit, so I simply took the module that the compiler was complaining about and declared it explicitly. But, that’s just my opinion.

@slavafomin it worked for me in a similar case in another project, when I’ve put a new index.d.ts in the project root directory (i.e. in the same directory as the tsconfig.json is located).

i found this to be a helpful write up. https://medium.com/@chris_72272/migrating-to-typescript-write-a-declaration-file-for-a-third-party-npm-module-b1f75808ed2

in my case i just had to place the migration file in src/@types/@okta/library-name/index.d.ts and as long as the part after @types matched the import, it was picked up. inside can be just 1 line declaring the module

You can put it anywhere as long as tsc can locate it. I.e. using files or include in tsconfig.json.

I put them under a custom-typings folder.

So it’s loading the module via the .js file also it seems. Do you have ‘allowJs’ set in your project config?

tried all the solutions not working! 😦

I took @SCLeoX’s suggestion and made the pattern-matching a bit narrower.

- declare module '*' {
+ declare module '*.js' {
   const value: any
   export default value
 }

it seems too heavy a burden to require everything to have a @types

you do not need to include @types. just add:

declare module "foo";

Thanks I ended up forking and making a pull request with typings and adding an index.js outside the lib, which solves the issues

@aluanhaddad – yes ofcourse. sorry, that was a typo! updated my post

@balajikris Have you tried:

declare module 'adal-node' {
    var _a: any;
    export = any;
}

instead?