Typescript- A Different Kind of Error

Published on 06 Jul 2020 by Dave Regg

Simply put, Typescript is a strict form of JavaScript. There are many reasons why people find JavaScript a weird programming language. One of those reasons is the flexible variables. In other languages such as Java or C#, a developer must declare the type of variable, like string myName = "Dave";. Therefore, any time you change the content of the variable, it must remain that type. For JavaScript developers, you may declare a variable let myName = "Dave"; and change that type later in the code myName = 42; without error.

Typescript creates a stricter environment for JavaScript developers. With Typescript, expectations are given to variables, classes, and objects in order to run a program without mysterious type-errors. It makes JavaScript less weird, it gives the developer a more descriptive error message, and it is creates a better flow to the code. It is also an Object Oriented language, so it can lead a newer developer into a progression from JavaScript to an Object Oriented Language.

Getting Up and Running

Typescript is a language that needs to be compiled, meaning the files are created, and then packed up and reloaded as JavaScript files. Typescript files are first created with a .ts extension, and when $tsc [filename] is run, the .ts file will be compiled and update the .js file of the same name. Therefore, the html file where the developer wants the .ts content to run is placed in the html file as the .js file, because that is the code that the HTML is actually running.

  • app.ts is created with Typescript code

  • $tsc app.ts compiles the code and creates app.js

  • index.html runs app.js with <script src="app.js"></script> at the end of the body tag.

The developer could take this further with a $tsc init command which will then create a tsconfig.json file. This file allows the developer to play around with Typescript options, like what directory .ts files are compiled to, or what version of JavaScript it compiled to. Webpack allows even further modifications. Check out the docs for more information.

typescript-example-1

The Basics

Like the C# example earlier, Typescript allows developers to create strict variables let myName: string = "Dave";. This means that every time myName is redefined, it must remain a string, or the .ts file will not be compiled. In fact, an error will run giving the developer the exact line and reason as to why the file did not compile. Other datatypes that are straightforward are booleans and numbers.

Arrays are more complex because they are a collection of datatypes. A developer can declare the type of data an array should expect let numbers: number[] = []; and simply push that datatype in the array without error. But what if the developer wants more than one type? That's when it can get a bit more complex let mixedArr: (string|number)[] = []; where the array will not allow both strings and numbers. The developer can also use a pipe, |, for variables. For example, let myAge: number|string = 42; might need to swap to a string later in the code to display in HTML. It can now be rewritten as myAge = "42"; without error.

Finally, Objects can we written in several different ways, but as soon as they are defined, the developer may not create a new property and insert it into that object. The first way is to create a variable and save it as an object. let firstPerson: object; can be created and then overwritten once firstPerson = { name: "Dave", age: 31 }; but if the developer wants to add something later, firstPerson.city = "Philly"; will throw an error.

A second way is to define the variable as an object let myObj = { name: "Dave", age: 31, city: "Philly" }; but like all objects, the property types are written in stone. name cannot change to a number or it will throw an error. Also like all objects, the developer may not add another property onto an existing object.

The final way is to explicitly write what the object will look like before writing the content. This is like creating a Class for the object but without the reusability. In actuality, it helps developers that inherit the code see what an object is to expect. let personTwo = { name: string, age: number }; can later be populated personTwo = { name: 'Bruce Wayne', age: 24 }; without error.

Typescript Functions

Functions are simple once the basics are down. A developer may declare a variable as a future function let greeting: Function which is declared with a capital F, and is good practice for later developers that inherit this code. All functions will output void as default, but an expected return can be written explicitly after the parameter parantheses. let greeting = (): void => console.log('Hello world!'); returns nothing, so it is void. However, let add = (a: number, b: number): number => a + b; will return the value of a + b which is expected to be a number.

The latter example shows that parameters are also defined with a type. Parameters also accept optional parameters which is displayed with a question mark. const greeting = (name: string, greeting?: string): string => { return greeting ? `${greeting} ${name}!` : `Hey there ${name}.`; has an optional parameter which will change the outcome of the function. Default parameters can also be defined with an equal sign. const greeting = (name: string, greeting: string = 'Hi'): string => `${greeting}, ${name}!`; allows the default value to take over if a greeting is not given.

The final, and most explicit way, to define a function is with a signature. let add: (a: number, b: number) => void; where parameters a and b can be anything when the actual function is written. However, this only shows what function add expects later in the program. add = (numOne: number, numTwo: number) => console.log(numOne + numTwo); will work fine. However, if the developer were the return the actual number, an error will be thrown.

typescript-example-2

Classes and Objects

There are three basic ways an Object can be created, displayed above. From this point forward, I will refer to each option by variable name.

PersonOne declares each property with the type that is expected. The constructor is a special method which created the object using the method. The constructor defines the parameters expected when a new object is created, and sets those parameters to the properties on the object. this.name = n; is setting the name to the user input. Finally, format is a method that can be run by any instance of the class to format the information into a string. By default, when accessibility of properties is not declared, all properties are public, meaning the developer can read or overwrite a property at will.

PersonTwo shows accessibility of each property while it is being declared. The three options are public, private, and readonly. Private properties can never be overwritten, and can only be read through a class method, such as PersonTwo.format(); because it is accessed in the Class. Otherwise, if the developer were to try myPerson.age; an error would occur. Readonly allows access to reading the property with myPerson.job; but changing that property will not be allowed myPerson.job = 'Construction';.

Finally, PersonThree displays how to create a Class with shorthand. However, this method is only allowed when the developer explicitly states the accessibility of the properties. Otherwise, an error will be thrown.

typescript-example-3

An Intro to Interfaces

Interfaces are still new to me and I'm trying to grasp the concept of them. In my mind, it is what a Class or a Function is expecting. If a Function is expecting an object parameter that needs a name, but the parameter does not have a name then the function will cause an error. Using an interface will have the parameter declare the need for a name in order for the function to be useful.

In the Function example above, the interface describes the look of the Object. It is expected to have a name, an age, and a speak function. If an Object declared as a IsPerson interface is declared with additional properties, or without one of those properties, an error runs.

Then the function greetPerson makes use of the interface by declaring the parameter as that specific interface. This ensures that the person parameter inserted into greetPerson has to have a name property. If not, an error is thrown and Typescript will give the exact location and reason as to why the error has been thrown.

Classes can be created by extending those interfaces. Multiple classes can make use of the HasFormatter interface in case there is a function later in the code that makes use of the format() function. If the function does not have a class that includes HasFormatter, then an error will run which will once again specifically state the placement of the error.

let Summary: string = "Typescript is Important!"

Typescript is incredibly important when it comes to well-written, strong programming practices. It makes code easier to read, and defines exactly where errors come from because variables and objects are expecting certain datatypes. There is definitely a learning curve when using Typescript, but I believe it is well worth looking into if you want to go to the next level in terms of good practices.

This articles only shows the very basics of Typescript. It comes with additional types such as Generics and Enums, it works with React, Angular, and other popular frameworks, and also has specific rules for DOM manipulation. For further reading, check out the documentation.