Search code examples
typescripteslinttypescript-eslint

Typescript prevent inferring types except at variable declaration


There's a few questions around implicit any types in Typescript but none that I've found answer my question.

Say I have this:

let thing;
thing = 'someValue';
thing = 'someOtherValue';

The variable thing will now have the type any.

enter image description here

How can I prevent this situation where a variable is declared without a type annotation AND without being immediately assigned a value with a concrete type? I'm using ESLint and found the rule @typescript-eslint/no-unsafe-assignment but that doesn't cover this case.

PLEASE NOTE the suggested duplicate doesn't really answer my question. I already have strict enabled in the TS compiler options, which causes noImplicitAny to also be enabled, however noImplicitAny doesn't do enough for me.

What I want is to not be allowed to create a variable of type any except by explicitly annotating the type as any. It's very inconvenient that a variable created near the top of a block can have its type inferred many lines further down AND in multiple places, meaning my IDE can't tell me the type until after I've used the variable. I would much rather that my types must be declared at the time I create the variable.

Examples:

// Good
let thing: string;
...
thing = 'someValue';

// Good
let thing = 'someValue';

// Good
let thing = SomeFunctionWithAnnotatedReturnType();

// Bad
// This is what I want to prevent
let thing;
...
thing = '123';
...
thing = 123;

Solution

  • After discussions between many people and much googling, I eventually proposed a Typescript ESLint rule. To my great surprise, what I want is already possible with the following ESLint rule, seen working here:

    "no-restricted-syntax": [
        "error",
        {
            "selector": "VariableDeclaration[kind = 'let'] > VariableDeclarator[init = null]:not([id.typeAnnotation])",
            "message": "Type must be inferred at variable declaration"
        }
    ]
    

    I didn't know that was possible and it opens up a whole lot more possibilities.