Discovering TypeScript

160
0

I used to like JavaScript. But ever since I discovered TypeScript, my programming life has changed and I haven’t looked back ever since. In this article I hope to convince you to jump on the bandwagon and boost your career.

Hang Loose?

A lot of people like JavaScript. Indeed it is one of the most popular languages according to several sources. But it’s kind of misleading. JavaScript is primarily used for the client-side, or front end as it’s sometimes called as well, whereas more popular languages, such as Python or Java  are used primarily for the server side (Java also has the advantage of also being used for Android development).

JavaScript, like Python, is a loosely, or dynamically-typed language. What does it mean?

In a lot of languages you need to declare the variable type before using it. This is essential for compiler optimization. Once the compiler “knows” the type, it can allocate the necessary memory in a safe way. This is called statically, or strongly-typed.

JavaScript does away with this by being loosely-typed. This means that it doesn’t require you to describe the variable type. Actually it doesn’t even let you.. It could be anything anytime. The compiler will infer the type from the given value. In JavaScript land this is perfectly valid code:

 let a = 1
 a = ‘hello world’
 a = {}
 a = [] 

There are reasons to like this approach. There’s less typing overhead, you can reuse a variable once done with its initial value etc. In a sense, it’s like having a door closer. You don’t have to worry about leaving the door open. It will take care of itself.

But that’s also the downside. A closed and a locked door are two separate things. And once you don’t have to worry about closing it, you’re likely to forget about locking it as well. Somewhere down the road there is a compiler which will do a more efficient job in running your code, if it knows that the type will not change. Somewhere there may be a function waiting to do something with that value. Can you be certain that you didn’t change the value type by mistake?

Consider the following question: is a phone number a number? Wait, what? Is that a trick question? Not really.

Here’s a number: 800800123

Here’s the same number: 800-800-123

Obviously the first one COULD be a number, while the second couldn’t.

So let’s add a dialing code.

1+800800123 === 800800124

Not what you aimed for, right?

But do it slightly differently and…

1+’800800123’ === ‘1’+’800800123’ === ‘1800800123’

Do you realize how detrimental a mistake in a value type could be?

So now what?

TypeScript to the Rescue

TypeScript was developed by Microsoft as a superset of JavaScript. This means that in TypeScript you could still use standard JavaScript no problemo, but with plenty of added sugar on top and safe measures to guard your code. It allows you to write statically-typed code, which will look familiar and feel comfortable for anyone coming from a programming background. Moreover, it will warn you when you try to expect one type and provide another, or try to re-assign a variable with a non-compatible type. 

Behind the scenes the TypeScript engine will compile your code down to standard JavaScript.

A regular JavaScript variable definition will look like this:

let a = 1

In TypeScript you’d write it like that:

let a: number = 1

But actually TypeScript is smarter. It can infer the data type if assigned, so the following lines will pass in standard JavaScript, but fail in TypeScript:

 let a = 1
 a = ‘hello world’
 A standard function will look something like this:
 function sum(a: number, b: number): number {
             return a + b
 } 

Notice that we’ve specified both the param as well as return types. So TypeScript will check both:

 sum(1, 2) // works
 sum(1, ‘2’) // error
 let a: number = 1 + sum(2, 3) // works
 let b: string = 1 + sum(2, 3) // error 

TypeScript is catching so quickly, that ever since React started supporting it, many developers have shifted to using it as well. Angular has been using it from day one, and you can “typed” versions of many popular NPM packages.

A Class Act

We’ve barely scratched the surface with the language’s abilities. Throwing functions here and there is just the wrong way of doing things, so just like any serious object-oriented typed language, here we are encouraged to use classes in order to organize our code.

Now classes in JavaScript are nothing new. They’ve been around ever since ES6. However its been a very primitive implementation of a class system. TypeScript’s implementation is much more akin to regular classes.

Here’s a standard class implementation in TypeScript

 class MyClass {
     public static className = 'MyClass'
     private secret = 'secret'
     public info = 'info'
     constructor() {
         console.log('hello world')
     }
 } 

Notice the field modifiers. They should be instantly familiar to you if you’re coming from aan OO language, but don’t exist in JavaScript. If you try to access ‘secret’ from a class instance the compiler will yell at you, As you can see you can also use static modifiers, to be accessed from the class level over the instance level. Naturally this extends to class methods as well.

 class MyClass {
     public static className = 'MyClass' // MyClass.className
     private secret = 'secret' // Can’t access from the outside
     public info = 'info' // Publicly available
     constructor() {
         console.log('hello world')
     }
     private secretFunc() {
         // can't access from outside
     }
     publicFunc() {
         // no need to specify the modifier - it's public by default
     }
 } 

But it doesn’t stop there either. Besides inheritance you can also use interfaces as well.

But TypeScript allows us to go even beyond that. We can also implement abstract classes and methods.

 abstract class MyClass {
     foo(): void {}
 }
 class NewClass extends MyClass {
     foo(): void {
         console.log('foo')
     }
 }
 const mc = new MyClass() // No go!
 const nc = new NewClass()
 nc.foo() 

Advanced Types

Being constantly evolving, TypeScript allows you to define custom types. Imagine a variable representing a coordinate. It could be something like a numerical tuple, like so:

const coord: [number, number] = [1, 2]

But what if you don’t remember which number represents the longitude and which one the latitude? No worries, we’ve got you covered:

const coord: {lon: number, lat: number} = {lon: 1, lat: 2}

And you can define that structure as a standard type in your program:

type coordinate = {lon: number, lat: number}

const c: coordinate = {lon: 1, lat: 2}

You didn’t think we’d stop there, right? There’s also union types.

Imagine a function which takes either numbers or strings and concatenates them. In JavaScript it may look like this:

function concat(a, b) {

    return a.toString() + b.toString()

}

console.log(concat(1, 2))

console.log(concat(‘1’, ‘2’))

Seems legit. But what prevents us from doing this?

concat({}, [])

Well, it’s JavaScript. Nothing! Let union types come to our rescue and protect our function’s sanctity!

function concat(a: number | string, b: number | string) {

    return a.toString() + b.toString()

}

Isn’t that great?

Be Generic

Over the years TypeScript has evolved greatly and adopted many features from standard languages. One of them is generics. Not a super simple topic to tackle. Some users avoid it like the plague out of fear, but it’s still quite useful.

So what is a generic? Sometimes we don’t want to be too specific about the type we pass to a function. We may wish to allow a function to handle a type which has some characteristics, such as being an extension of a specific class.

Let’s look at an example. Suppose we wish to create and manipulate an array of a certain type. It could be any type, but the type has to be identical all along (this is a very naive example, since TypeScript already has a typed array type).

JavaScript would force us to manually check each entry we’re trying to add to the array. TypeScript adds generics to our rescue instead:

 class TypedArray<T> {
     private arr: T[] = [];
     add(val: T) {
         this.arr.push(val)
     }
     getValue(): T[] {
         return this.arr;
     }
 }
 const a = new TypedArray<string>()
 a.add('hello')
 a.add('world')
 a.add(1) // No go
 const b = new TypedArray<number>()
 b.add(1)
 b.add(2)
 b.add('hello') // No go 

TypeScript gives us a ton of depth with generics. For example we can force generics to be a specific type, not just any type.

 class FooBar {
     foo(): void {}
     bar(): void {}
 }
 class FooBaz extends FooBar {
     baz(): void {}
 }
 class TypedArray<T extends FooBar> {
     private arr: T[] = [];
     add(val: T) {
         this.arr.push(val)
     }
     getValue(): T[] {
         return this.arr;
     }
 }
 const a = new TypedArray<FooBar>()
 const b = new TypedArray<FooBaz>()
 const c = new TypedArray<string>() // No go 

There’s much more to generics, but that would in itself justify a separate article.

Start Using TypeScript Right Away

By now I hope I’ve got you pumped up on TypeScript. So the big question is how do you start playing around with it. 

One option is to use one of many online playgrounds and play around with it. The first natural option is on its own homepage.

Another very popular option is CodePen. In order to use it there, you’ll first need to set up the TypeScript preprocessor. First create a new pen. Then click the cog icon next to the JS panel. Choose TypeScript as a preprocessor. And you’re good to go.

Both options are valid, but lack a few features, such as file splitting. If you wish to experiment with larger projects but stay online, a good option is StackBlitz. You have several TypeScript-based options you can choose from, but if you want to experiment with a barebones project, just choose TypeScript – Blank Project.

Next is the more advanced stuff. Use it if you’re comfortable developing with JavaScript and NPM.

Once you feel comfortable enough you may wish to start your own project locally. Let’s see how to do it using VSCode. First of all you need to install it if you haven’t already.

Next you can either install TypeScript support using NPM. Alternatively you can install it from the VSCode marketplace.

What’s also very useful is to have a concurrent process which will restart your project once you save a change. 

If you’re doing a NodeJS project, I suggest you install ts-node-dev. Once installed add the following entry in the package.json under the “scripts” section:

“start”: “ts-node-dev –respawn src/index.ts”

If you’re developing for the front end. Install a bundler. The easiest choice is Parcel. Just install it and create a boilerplate project like this:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Document</title>
 </head>
 <body>
     <script src="index.ts"></script>
 </body>
 </html> 

Create a index.ts inside with the following code:

let a: number = 1

console.log(a)

Then run the Parcel command line:

parcel index.html

And then not only will your project launch in the browser, it will also run concurrently. It will also  detect changes very quickly and reload when necessary.

Conclusion

We’ve discussed what the limitations of JavaScript are and how TypeScript addresses them by adding types on top.
We also saw how popular OOP aspects are implemented and how to use advanced types, such as unions and generics.
Lastly we’ve explored the various options we have to start developing using TypeScript both online and offline.
Now it’s up to you to take your coding skills to the next level!

Happy coding.

Gil Steiner
WRITTEN BY

Gil Steiner

Senior software developer with game dev specialization. Currently doing full stack web dev and front end automation.