Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "allowImplicitAnyImports" compiler option for usage with "noImplicitAny" #15878

Closed
rummelsworth opened this issue May 16, 2017 · 11 comments
Closed
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript

Comments

@rummelsworth
Copy link

rummelsworth commented May 16, 2017

TypeScript Version: 2.3.2

Code

import _ = require('lodash')
// with 'noImplicitAny' compiler option and without '@types/lodash' package dependency

Desired behavior:

The compiler emits no error.

Actual behavior:

The compiler emits this error:

Could not find a declaration file for module 'lodash'. '/project/node_modules/lodash/lodash.js' implicitly has an 'any' type.

Motivation:

  • I want to use lodash (or any non-TS package) without types.
  • I want to have noImplicitAny turned on for my own code.
  • I want to not depend on @types packages, which for many JS packages do not exist. (And unfortunately some of the ones that do exist are poorly maintained.)
  • I want to not add .d.ts files for every non-typed third-party JS package I need to use.
  • I want to use TS's import-require (not var-require).
@ghost
Copy link

ghost commented May 16, 2017

#6615 should help.

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label May 16, 2017
@mhegazy
Copy link
Contributor

mhegazy commented May 16, 2017

More docs available at http://www.typescriptlang.org/docs/handbook/modules.html#shorthand-ambient-modules

@rummelsworth
Copy link
Author

Thanks. From those resources, the recommendation seems to be "Add one file to your project that contains a declare module 'xyz' line for each module xyz you want to import as any."

This is not ideal, but it works. I'd rather not have the extra file, and I'd especially rather not have to add a line to that file for each any module I need, but it's not as invasive as I feared from my first readings of related issue threads and the above-linked resources over the past few days.

Still, it would be much better to have the compiler option. But if it's already been reviewed and decided against by the team, that's fair.

@ghost
Copy link

ghost commented May 16, 2017

There's also declare module "*"; that will make unknown modules any by default.

@rummelsworth
Copy link
Author

rummelsworth commented May 16, 2017

Thanks, I missed that. I thought it was going to make all modules any.

However, with declare module '*' I see that I lose module resolution's ability to provide an error when it can't find the module. This moves a very convenient compile-time check to a potentially confusing set of one or more runtime errors.

What's the rationale against this compiler option? That this issue was tagged "Question" instead of "Suggestion" when I was aiming for the latter implies one exists, I think.

From the discussions I've read in the issues, and from the current lack of a usage pattern that is both non-invasive and exactly equivalent, it seems like the rationale is that its benefit to the user doesn't outweigh the cost to develop it. But if that were true, this should be tagged "Suggestion" instead of "Question", since I'm assuming one measure of user benefit is how many users indicate they would benefit from it.

Would something in TS break or become inconsistent if this compiler option existed?

@rummelsworth
Copy link
Author

Could someone please remove the Question label and add the Suggestion label?

I'm asking because this issue was drafted as a suggestion, not as a question, and the suggested functionality is not fully provided by the (still very helpful) workarounds given by the team here and in other issues' discussions.

For other TS users out there who (a) have encountered this same deficiency in TS, (b) want this compiler option, and (c) are browsing and searching the issues, the labeling should indicate that this issue is a valid suggestion --- unless it isn't, but that hasn't been explained (or even asserted).

Thanks.

@mhegazy
Copy link
Contributor

mhegazy commented May 26, 2017

Marking as suggestion. but i do not think we will be doing this any time soon.

The compiler has a default behavior of treating all imports with no associated declaration files as any. this allows you to skip the definition file search and acquisition step. But it is rightfully flagged under --noImplicitAny.

Allowing the any's from module imports to propagate defeats the whole point of using --noImplicitAny. --noImplicitAny at its core gives you safe refactoring guarantees; this is built on the fact that the compiler knows the types of everything explicitly. allowing module imports to leak implicit anys into your program breaks that assumption.

The language also has affordances for declaring modules, so you can declare specific modules that you do not have declaration files for as declare module "jQuery"; or as @andy-ms mentioned earlier go all the way to declare module "*";. So you already have 1. treat it as any if it exists, or 2. trust me I know what i am doing, having yet another third state adds complexity, reduces safety and not sure i see it adding much value.

@mhegazy mhegazy added Suggestion An idea for TypeScript Declined The issue was declined as something which matches the TypeScript vision and removed Question An issue which isn't directly actionable in code labels May 26, 2017
@mhegazy mhegazy closed this as completed May 26, 2017
@rummelsworth
Copy link
Author

rummelsworth commented May 26, 2017

@mhegazy Thanks for replying (and re-labeling).

Allowing the any's from module imports to propagate defeats the whole point of using --noImplicitAny. --noImplicitAny at its core gives you safe refactoring guarantees; this is built on the fact that the compiler knows the types of everything explicitly. allowing module imports to leak implicit anys into your program breaks that assumption.

This isn't in doubt at all. I'm with you 100% on this.

However, when you use an externally packaged module that is simply not actually (or correctly) typed, you have no choice but to deal with any and its leakages. However, that fact should not prevent you from using the benefits of noImplicitAny in the rest of your code.

The good news is that we have declare module, as you and @andy-ms have already explained (which I appreciate immensely).

The bad news is

  1. declare module '*' causes TS to not flag missing modules as errors, and
  2. declare module 'xyz' for each any-typed module xyz is verbose.

I feel like we're talking past each other and that this really comes down to a disagreement over whether "bad news 2" is actually bothersome.

@mhegazy
Copy link
Contributor

mhegazy commented May 26, 2017

However, when you use an externally packaged module that is simply not actually (or correctly) typed, you have no choice but to deal with any and its leakages.

this seems like one or n modules, and hopefully not all modules you deal with all the time ; and for that adding a declare module "foo"; seems like an appropriate fix untill you have the time and desire to write foo.d.ts.

However, that fact should not prevent you from using the benefits of noImplicitAny in the rest of your code.

what i am arguing here is that you are not using the benefits of noImplcitAny here. the flag's value is not that most of your code has types, it is that all your code has types.

declare module 'xyz' for each any-typed module xyz is verbose.

and this is the intention. the idea is you made a conscious decision to treat some modules as any, and you are aware of the implications.

@rummelsworth
Copy link
Author

the flag's value is not that most of your code has types, it is that all your code has types.

I think I'll have to defer to your experience on this one, because I can only offer the single data point of my own project as counter-evidence. My colleagues and I have definitely benefited from noImplicitAny even though we use a few any-typed modules. The leakage of any has been easy to isolate where it occurs.

I agree that the workarounds are appropriate and not usually a big bother. From my own viewpoint though, they leave a small gap where there's actually a valuable user story. I have to admit I can't argue that the value is non-negligible at this point, though.

Thank you both for the help and insight.

@borekb
Copy link

borekb commented Oct 6, 2017

the flag's value is not that most of your code has types, it is that all your code has types.

I think that's too strong of a statement, the flag is just about preventing implicit anys.

What seems strange to me is that variables and consts can be marked with any easily while imported symbols need this quite unintuitive solution with a new .d.ts file and declare module '...' for each untyped package in it.

For reference, import foo: any from "module"; has been proposed in #3019 (comment). I'm not saying this specific syntax is great but it's conceptually much closer to what I'd expect. Also the allowImplicitAnyImports compiler option proposed here makes sense to me.

For me, it comes down to usability: in the world of various npm modules, untyped imports are quite common and it's currently not intuitive how to deal with it easily. I've seen people just doing require() instead of import which is a strange workaround and maybe suggests that there is some slight usability problem in TypeScript in this area.

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants