September 16, 2015
Converting JavaScript to TypeScript – Common Problems
Converting JavaScript code to TypeScript
Here at theCodeCampus and w11k we are using TypeScript in web projects for 12 months now. Our experiences with TypeScript are overwhelming so far! Using TypeScript is a huge improvement over a JavaScript-based development, especially in larger projects.
One of TypeScript’s advantages and often communicated characteristic is that its syntax is a (typed) superset of JavaScript. Hence, existing JavaScript code is valid TypeScript code. So far, so good! The selling point is that you can easily take existing JavaScript code and convert it to TypeScript, simply by changing the file extension from ‘js’ to ‘ts’.
Problem 1: Inferred ‘any type’
When new TypeScript users try this in practice, they often experience this error message:
1 |
error TS7006 Parameter 'methodParam' implicitly has an 'any' type. |
The reason for this is quite simple: When e.g. a method parameter does not declare a type (which isn’t possible when the code used to be valid JavaScript), the TypeScript compiler warns that the ‘any type’ was inferred. Let’s say your method looks like this:
1 2 3 |
function myFunction(methodParam) { // ... } |
The solution is to simply explicitly add a type, either the ‘any type’ or a more precise one. Both declaration below would work:
1 2 3 |
function myFunction(methodParam: any) { // ... } |
1 2 3 |
function myFunction(methodParam: string) { // ... } |
Another solution is to change the behavior of the TypeScript compiler. How to do this, depends on the way you used to invoke the compiler. The command line tool ‘tsc’ uses the flag ‘–noImplicitAny’ to toggle this behavior. If you use a tsconfig.json (what you hopefully do), you can alter the compiler flags there:
1 2 3 4 5 |
{ "compilerOptions": { "noImplicitAny": false, } } |
However, I highly recommend to leave this flag on or respectively to add this flag to the ‘tsc’ invocation. After all, you want the compiler to assist you in writing better code and adding reasonable type annotations to your variables is one part of it.
Problem 2: Inferred Structural Types for Object Literals
Take the following perfectly valid JavaScript code:
1 2 3 4 5 6 7 8 |
var obj = { key1: 1, key2: 2 }; if (CONDITION) { obj.key3 = 3; } |
We first initialize the object ‘obj’ with 2 properties. Then, based on a condition, we add another property ‘key3’. If the condition is false, the expression ‘obj.key3’ will evaluate to ‘undefined’. All this is common JavaScript code. However, if we pass this to the TypeScript compiler, we get an error message:
1 |
error TS2339 Property 'key3' does not exist on type '{ key1: number; key2: number; }' |
The reason for this is that our object literal used to initialize the ‘obj’ variable also creates a ‘structural type’ consisting of two properties: ‘key1’ and ‘key2’. When we try to assign the property ‘key3’, the compiler rightfully complains that this type has no property ‘key3’.
There are two possible solutions for this. We can add this property to the structural type:
1 2 3 4 5 |
var obj = { key1: 1, key2: 2, key3, undefined }; |
Or, we declare the variable ‘obj’ with the ‘any type’:
1 2 3 4 |
var obj: any = { key1: 1, key2: 2 }; |
If possible, I recommend to always choose the first solution.