Typescript prevent inferring types except at variable declaration

Viewed 63

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;
2 Answers

I can’t leave a comment as I don’t have enough reputation, but I find your question doesn’t make a lot of sense. You don’t want to annotate a type or give it a value while at the same time not allowing it to have the type any? What type exactly do you want it to have when giving no indication of a type?

If you want it to be able to have a few specific types later down in your code then you can annotate many types for one variable.

let thing: string | number

This way, typescript will allow thing to be a string or a number, but nothing else.

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.

Related