Typescript: noimplicitany and module without typings

Created on 8 Jan 2017  ยท  19Comments  ยท  Source: microsoft/TypeScript

tsc 2.1.4

In 2.1 tsc support import module as any if they are installed through npm but no typings is found.

With --noImplicitAny, this is prohibited, meaning user need to get all typings for all modules again.

Should we consider this as an exception case for --noImplicitAny?

Needs More Info

Most helpful comment

Hello there!

I have this module, called s3fs in my project, which doesn't provide any typings. I wanted to test it out, but I can't find a way to import it in my file without getting errors from compiler.

This line:

import S3FS = require('s3fs');

Gives me:

error TS7016: Could not find a declaration file for module 's3fs'. 'โ€ฆ/node_modules/s3fs/index.js' implicitly has an 'any' type.

How do I make it explicitly any?

If I try to use declarations to handle this, then I'm getting this error:

error TS2665: Invalid module name in augmentation. Module 's3fs' resolves to an untyped module at 'โ€ฆ/node_modules/s3fs/index.js', which cannot be augmented.

@mhegazy could you elaborate please? Thanks!

All 19 comments

Should we consider this as an exception case for --noImplicitAny?

why?

Because users can benefit from --noImplicitAny and advanced control flow analysis while able to keep working if using libraries that do not have typings available.

By the way, would this consider explicit and remedy the situation?

import * as Something from 'some-module-without-typings'

declare module 'some-module-without-typings/*'

all you need is to declare the module. so something like

declare module 'some-module-without-typings/*' {
    var _a: any;
    export = _a;
}

Is an even more general solution having this?

declare module '*' {
    var _a: any;
    export = _a;
}

Is an even more general solution having this?

All you need is declare module "*";

For this to be seamless we really need a solution for #12971

Hello there!

I have this module, called s3fs in my project, which doesn't provide any typings. I wanted to test it out, but I can't find a way to import it in my file without getting errors from compiler.

This line:

import S3FS = require('s3fs');

Gives me:

error TS7016: Could not find a declaration file for module 's3fs'. 'โ€ฆ/node_modules/s3fs/index.js' implicitly has an 'any' type.

How do I make it explicitly any?

If I try to use declarations to handle this, then I'm getting this error:

error TS2665: Invalid module name in augmentation. Module 's3fs' resolves to an untyped module at 'โ€ฆ/node_modules/s3fs/index.js', which cannot be augmented.

@mhegazy could you elaborate please? Thanks!

@mhegazy I get error TS2664: Invalid module name in augmentation, module '*' cannot be found.

Or when I try to be specific in my case I get: error TS2665: Invalid module name in augmentation. Module '@material/checkbox' resolves to an untyped module at 'T:\node_modules\@material\checkbox\index.js ', which cannot be augmented.

I would love to have an import as an explicit any.

Should we consider this as an exception case for --noImplicitAny?

why?

because otherwise this simple use case is a pain in the neck?

@mhegazy I get error TS2664: Invalid module name in augmentation, module '*' cannot be found.

This means you are putting the declare module in a module file.. just put the declaration in a .d.ts file that is not a module (i.e. does not have export or import on the top level).

@mhegazy Is there still no way to make the any type of an untyped import explicit? I want to use noImplicitAny in my codebase, which has a relative import of a plain JavaScript module that is _in the source tree_. Normally, I would just install the module using NPM and then declare it, but since we have had to modify the module and may have to modify it extensively, and since the module is inactive upstream, I've just merged it into our tree (abridged, below):

.
โ”œโ”€โ”€ lib
โ”‚ย ย  โ”œโ”€โ”€ core.ts
โ”‚ย ย  โ”œโ”€โ”€ js-type-layer.ts <-- The TS module that imports and provides the JS module
โ”‚ย ย  โ”œโ”€โ”€ api.ts
โ”œโ”€โ”€ vendor <-- The plain JS module directory
โ”‚   โ””โ”€โ”€ js-module
โ”œโ”€โ”€ node_modules
โ”‚ย ย  โ””โ”€โ”€ @types
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ package-lock.json
โ””โ”€โ”€ tsconfig.json

Currently I do the following in a TypeScript module with "noImplicitAny" : false:

import _m = require("../vendor/grove-js");

declare namespace grove {
    //...
}

export default _m;

If I enable noImplicitAny, then the first line errors, as _m is implicitly typed as any. But, you cannot declare a relative module in TypeScript, so it's not possible (afaict) for me to convert this into a declarations file and declare the grove module that way.

This seems like a bug to me, since the error is _not_ that the type of the import is any, only that that type is implicit, and there doesn't seem to be any way for me to make that type _explicit_. Hacking away TypeScript's module resolution checker by doing declare module "*" doesn't seem like a good solution, and even when I do use declare module "*", I get errors about namespace '"*"' has no exported member ...

It's simple enough for me to leave noImplicitAny off in my project, but it's a shame to overlook this feature because I want to import a JS library using a relative import.

why not create a grove-js.d.ts file and put it next to the .js file?

This results in grove-js.d.ts is not a module. Then I change the import line to import grove from './grove-js/' and change the .d.ts file to specify declare module "*grove-js/" and this _seems_ to satisfy tsc, but then I turn on noImplicitAny again, and the result is the same: the import is any-typed.

Can you share a repro?

also, it seems onerous to require the creation (and continual maintenance) of a .d.ts for _every_ imported .js library just to enable the project-wide noImplicitAny flag.

surely if you're importing a .js file doesn't that import itself _explicitly_ declare that everything imported is of type any (unless the compiler can infer otherwise) ?

also, it seems onerous to require the creation (and continual maintenance) of a .d.ts for every imported .js library just to enable the project-wide noImplicitAny flag.

First, --noImplicitAny tells the compiler to raise a warning whenever it sticks an any type on a name that the user has not specified. a module import from an unknown and un-typed module fits that description.

Second, you do not need a file unless you want to go into details of the module declare module "foo"; is all you need. see http://www.typescriptlang.org/docs/handbook/modules.html#shorthand-ambient-modules

I prepared a tiny repo, which

  • has an index.js file
  • an index.d.ts

when setting "noImplicitAny": true tsc fails :(
i believe that is what @Spongman and @willmtemple mention.
would love to see help on that
https://github.com/wolframkriesing/implicit-any-and-js-files/commit/5bdb2bc403df8d272bb514dbc1d1081dad8ae06e

UPDATE: updated link, had to ensure that the d.ts is really used by tsc

@mhegazy i think the repo above reproduces the behavior described above

@mhegazy you can check out https://github.com/LaboratoryForPlayfulComputation/pxexec-runtime as well. We're trying to type the grove-pi javascript library. As is, I have lpc-grove-translation.ts and a module in lpc-grove-js/index.js. Currently, this repository is in a stop-gap state where it works but doesn't actually typecheck (seems like the namespace grove declaration doesn't bind to the export at the end, which I expected. In fact, I cannot use the noUnusedLocals compiler check because it sees declare module grove as _unused_.

When I want to typecheck the code, I rename lpc-grove-translation.ts to lpc-grove-js.d.ts and comment out the module declarations in the file. This gets me typechecking but the resulting error is that lpc-grove-js is not a module.

Again, if I were importing this library using npm, this would be very simple to do, as I would just declare the module in a declarations file, but I cannot, as far as I can tell, declare a relative path import,

Was this page helpful?
0 / 5 - 0 ratings