To wrap this chapter up, let's write another example. This time, we will write an unsafe program and then we will see how we can make it safer using TypeScript.
Our program will be a simple calculator. For the sake of the example, our calculator will only be able to multiply values together, but don't hesitate to extend the example to include other operations as well.
Create a new file and call it calculator.ts. In that file, add the following code:
function multiply(a, b) {
const result = a * b;
console.log("The multiplication of "+a+"*"+b+" equals to :
"+result);
return result;
}
multiply(1, 2);
multiply(2,2);
multiply(-10,10);
//multiply('foo', "bar");
We've used const this time because the calculation result should never be changed.
If you now compile and execute this calculator (using tsc calculator.ts, remember?), you'll see the results of our calls to the multiply function.
Everything seems fine so far, as shown here:
$ node calculator-unsafe.js
The multiplication of 1*2 equals to : 2
The multiplication of 2*2 equals to : 4
The multiplication of -10*10 equals to : -100
However, that code isn't very safe. What if you uncomment the last line? Do you think it makes sense to multiply strings together when doing calculations?
Now, indeed, the output is more problematic:
$ node calculator-safer.js
The multiplication of 1*2 equals to : 2
The multiplication of 2*2 equals to : 4
The multiplication of -10*10 equals to : -100
The multiplication of foo*bar equals to : NaN
Is this a behavior that you had intended? Probably not! The main problem that you have here, since that code is actually again mostly JavaScript, is one of expressiveness; you cannot easily/clearly state which types you expect as an input of the function. This is really unsafe because you could pass just about anything to your function.
You can, of course, write safer code in JavaScript, but at the expense of readability and conciseness.
Now, let's see how TypeScript can help. Actually, without you knowing, it already does!
Try to add this line to the code: multiply(1). This lacks an expected parameter. In pure JavaScript code, this would be alright, but TypeScript's compiler does complain now: TS2554: Expected 2 arguments, but got 1.
Let's go further now. Adapt the code as follows to specify the types that you expect:
function multiply(a: number, b: number) {
const result: number = a * b;
console.log(`The multiplication of ${a}*${b} equals to
${result}`);
return result;
}
multiply(1, 2);
multiply(2,2);
multiply(-10,10);
multiply("foo", 'bar');
We now have changed the console.log call to make use of a template string. Doesn't this make the code more readable? Also, take a look at the generated JavaScript code for this line: console.log("The multiplication of " + a + "*" + b + " equals to " + result);. As you can see, TypeScript has replaced our template string, making the code compatible with ES3.
As you can see, we can easily specify variable types using the : type notation, including for function parameters.
If you try to compile the program again, you'll see that TypeScript now helps us to avoid more mistakes:
$ tsc calculator-safer.ts
calculator.ts:10:10 - error TS2345: Argument of type '"foo"' is not assignable to parameter of type 'number'.
10 multiply("foo", "bar");
~~~~~
Isn't this wonderful? But wait, there's so much more yet to discover!