Skip to content

Suggestion: noInferredAny #39633

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

Open
4 of 5 tasks
mprobst opened this issue Jul 17, 2020 · 4 comments
Open
4 of 5 tasks

Suggestion: noInferredAny #39633

mprobst opened this issue Jul 17, 2020 · 4 comments
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@mprobst
Copy link
Contributor

mprobst commented Jul 17, 2020

Search Terms

noImplicitAny inference any noInferredAny

Suggestion

Symbols typed as any reduce the type safety of a program. That's fair if the programmer intended to use any. However it's relatively easy to end up with symbols typed any through type inference chains that are not obvious:

  • 3rd party libraries might return any
  • complex type expressions might infer to any
  • some .d.ts types default generic arguments to any (e.g. Set)

In all these situations, a programmer might write const foo = something(); and expect foo to have a reasonable inferred type. foo being inferred to any is easy to miss in such code, both while editing and while reviewing code.

Proposal: add a compiler option noInferredAny that flags symbols whose type is any and that do not have an explicit type annotation.

Use Cases

  • better type safety for programs
  • detect weak typings in your dependencies
  • more

Examples

const foo1 = returnsAny();  // error
const foo2: any = returnsAny(); // ok
const foo3: string = returnsAny(); // probably ok, programmer gave an explicit type? could also require an explicit cast.
const foo4 = returnsAny() as string;  // ok

const {foo5}: {foo5: string} = returnsAny(); // ok

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@RyanCavanaugh RyanCavanaugh added Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript labels Jul 17, 2020
@RyanCavanaugh
Copy link
Member

So consider something like

// Elsewhere
declare function fn<T = string>(): T extends "foo" ? { p: boolean } : { m: any };

const k = fn();

Is this an "inferred" any because k.m has type any? If so, how does TypeScript perform an infinite examination of all potential properties (it can't)? If not, is the feature working? Does the access occur on k.m cause the error instead? Or on property access of k.m?

Thinking about this in terms of only binding an inference to a top-level binding just misses a lot of cases. If you keep poking at this hornet's nest you end up with the proposed --strictAny, #24737. We can revisit that one again later, or if you have more concrete proposal here for exactly what would count as an error and a demonstration of how that would work beyond basic examples, that'd be interesting too

@mprobst
Copy link
Contributor Author

mprobst commented Jul 20, 2020 via email

@stefee
Copy link

stefee commented Sep 5, 2021

For anyone finding this now and wondering if there is a solution, you can use typescript-eslint with the following rules:

  "rules": {
    "@typescript-eslint/no-unsafe-argument": "error",
    "@typescript-eslint/no-unsafe-assignment": "error",
    "@typescript-eslint/no-unsafe-call": "error",
    "@typescript-eslint/no-unsafe-member-access": "error",
    "@typescript-eslint/no-unsafe-return": "error"
  }

Links to the documentation for these rules can be found here: https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules

You can also add these rules, plus some others, using the recommended-requiring-type-checking preset:

  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
  ]

You must also add this to your eslint config to allow the eslint plugin find your ts project configuration which enables it to do type-checking:

  "parserOptions": {
    "project": "./tsconfig.json"
  },

Here's the full docs for the parser config: https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#configuration

@osdiab
Copy link

osdiab commented Dec 19, 2024

@stefee 's solution from a few years ago works, though I would love if this were built into TypeScript instead of needing to use typescript-eslint for it, since it is extremely slow and makes many spurious errors in the editor when files change, like this: microsoft/vscode-eslint#1321

I don't really care if any is being used in library code, but if in my own code I could have TypeScript throw an error basically identically to what Typescript ESLint does with the above set of rules; then that would be perfect for my use cases—so if that can act as a concrete proposal of what exactly counts as an error, and a demonstration of how it would work beyond specific examples, then I hope that remains interesting!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants