Typescript: Add flag to disable Type Inference for variables, Force to declare type

Created on 28 Oct 2018  路  5Comments  路  Source: microsoft/TypeScript

Suggestion

I would like to have a flag that would allow me to disable inference of types when declaring variables and assigning the value of a function:

//An error should be shown in this line:
const x = myFunction(); // inferring the type of x from myFunction can cause a lot of problems!!

//And should be corrected to something like this:
const x : string = myFunction(); // type not inferred, we can check now if the function actually returns a string

Use Cases

When I have a variable declaration and assign the value returned by a function, it infers the type of whatever the function returns:

const x = myFunction(); //Maybe myFunction() returns a string, a number, an array, whatever

If I change the return type to a Promise or to a compatible type, it will not show any warning or error, unless I use methods or properties of x that are not on the new type. This may lead to unwanted results.

Examples

  1. For example, when I have to migrate a function that returned a direct value (string, number, object, etc), to a function that returns a promise:
function myFunction() : Promise<string> { //or async myFunction()...
  ....
  return some_promise;   //Maybe before this returned a string
}
const x = myFunction();  //x was a direct value but Now it is a Promise!!, no warning!
if(x != undefined){      //x will never be undefined now because it is a promise!!
  do_something_important;
}

So, in this case, I forgot to change the code that uses the return value and no warning is shown. That will lead to unwanted results.

  1. Another example: fiddler
    If I had previously:
function myFunction() : string { return "some string"}

and then change it to:

function myFunction() : string[] { return ["some string"]}

If I was using this as:

const x = myFunction();
console.log(x.length);

then it will again, not show any warning, but the results will be unwanted.

In these cases, if the compiler would have forced me to declare the variable like:

const x : string = myFunction();

instead of inferring the type of x, then I would have gotten the correct warnings.

I created the question for this after a some research in stackoverflow and a fiddler test case of the second point.

The noImplicitAny is useless in this case unless you do not initialize variables when declaring them, but this would prevent the use of const. I'm having a lot of these issues specially when migrating code to promises.

Thank you very much!!

Checklist

My suggestion meets these guidelines:

  • [X] This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • [X] This wouldn't change the runtime behavior of existing JavaScript code
  • [X] This could be implemented without emitting different JS based on the types of the expressions
  • [X] This isn't a runtime feature (e.g. new expression-level syntax)

It meets all, the suggestion is to add a flag, that would be disabled by default anyway, and would only check code at compile time.

External Suggestion

Most helpful comment

This feels like it would be better suited to a lint rule. I think this works:

typedef

"typedef": [true, "variable-declaration"]

const x = 3;
   // ^ ERROR: 1:7  typedef  expected variable-declaration: 'x' to have a typedef

All 5 comments

This feels like it would be better suited to a lint rule. I think this works:

typedef

"typedef": [true, "variable-declaration"]

const x = 3;
   // ^ ERROR: 1:7  typedef  expected variable-declaration: 'x' to have a typedef

Well in my case I need to go to a process to add a library, even if it is just a linter, and besides, I really think this should be a feature in the language itself, we have the noImplicitAny, noImplicitReturns, noImplicitThis, etc, flags, why not have this or something similar?

Also, I was talking about inference when declaring variables that take their value from functions, not sure if type inference from constant values like the one in your example is necessary or even helpful, but for functions it can really make a difference and an external linter should not be needed for this in my opinion.

@frank-orellana Then where do you draw the line between simple type defs and complex ones?
The above code could just as easily be declared like:

let i =0;
// ^ ERROR: 1:5  typedef  expected variable-declaration: 'x' to have a typedef
while(i < 5) { ... }

Hey @Toxicable , I don't really understand your question, and I'm not talking about declaring variables and assigning a constant value like in your example, I'm talking about assigning values from functions, and trying not to rely on linters.

I am not saying your example is not one to take into consideration, but my use case, the one I explain is when you assign the value of a function to a variable when declaring it, that's when things can get confusing. did you see the jsfiddle I posted?

Anyway, If the only way to get this is with an external linter library then what can we do. But I really feel this should be something that should be packed into typescript out of the box,

Thanks!

I agree with @jack-williams - if you find value in this check, tslint has a rule for you. Our philosophy is typically that we want to be able to produce the best types possible with as few annotations as possible. The few issues this prevents aren't worth the extra hassle for most people.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fdecampredon picture fdecampredon  路  358Comments

RyanCavanaugh picture RyanCavanaugh  路  205Comments

metaweta picture metaweta  路  140Comments

chanon picture chanon  路  138Comments

blakeembrey picture blakeembrey  路  171Comments