Understanding TypeScript

Jijie Liu
The Startup
Published in
6 min readNov 1, 2020

Because our company chose Angular as the front-end framework, I started to using TypeScript instead of JavaScript. Now, I completely love TypeScript. It gives us some powerful weapons that JavaScript can’t provide:

  • Type System: TypeScript consistently checks variables’ type. This feature significantly lowers the chance of bugs
  • OOP: Although JavaScript has class since ES6, it still lacks a lot of useful concepts, such as abstract class, interface, generic, etc. These existed in TypeScript.
  • meta programming: TypeScript provides decorator , which can add extra configuration or extra logic to a function or a class. This is widely used in the framework like Angular and NestJS.

Besides, TypeScript offers all of JavaScript’s features. Because all the TypeScript codes finally are compiled in JavaScript.

In short, TypeScript is a superset of JavaScript. JavaScript is still very important for a typescript developer.

I learnt TypeScript from official TypeScript Handbook. This article presents the tools I found interesting in TypeScript.

Type

Type assignment

In TypeScript, there are two ways to assign the type to a variable (similar to Dart):

  • let a = 5 : the variable a is assigned as number implicitly.
  • let a: number = 5 : the variable a is assigned as number explicitly.

I prefer the first way since it ensures the variable has the type I want and it needs less the codes :)

Basic type

As JavaScript, TypeScript has the basic types, such as number, string, boolean, bigint, symbol, null, undefined. Besides, TypeScript has more.

unknown: It describes the type of variable that we do not know when we are writing an application.

any: It refers to any type. the variable with any type is the same as the variable in JavaScript.

There is an example to explain the difference between any and unknown . But in practice, I wouldn’t assign b as unknown because I know b is a number.

let a: any = 4; 
a.toFixed(); // OK, toFixed exists
let b: unknown = 4;
b.toFixed(); // Error, Object is of type 'unknown'.

null and undefined: these two are the same as those in JavaScript. However, when using the --strictNullChecks flag, null and undefined are only assignable to unknown, any and their respective types .

let a: string;
a = null; // Error, strictNullChecks is active

Union Type

In null and undefined, the string variable can’t be assigned by null . This problem can be solved by union type.

let a: string|null;a = 4; // OK
a = null; // OK

This kind of assignment ensures the variable can not be null if we don’t use union type. It avoids many bugs.

object

It is a type that represents the non-primitive type, i.e. anything that is not number, string, boolean, bigint, symbol, null, or undefined.

To define the types of the properties, we use {} :

type Text = { id: number, description: string };

Or, we can use an interface , which will be presented later.

Optional Chain

It is very useful when we visit a property of an object. For example:

  • a?.b: the object a may have the property b . If b isn’t existed, undefined is returned.
  • a!.b: the object a must have the property b . If b isn’t existed, an error is thrown.

Function type

Function type contains parameters’ type and return’s type

(firstName: string, lastName?: string) => string

That means a function takes firstName as a required parameter and lastName as an option parameter. Both of them has the string type. And the function return a value with the string type.

If the function returns nothing, we use void .

OOP

class

After ES6, JavaScript has class . The class in JavaScript can

  • extend another class
  • set static attributes and methods
  • create private or protected attributes and methods

TypeScript class can do these, too. Beside, The class in TypeScript can

  • create and extend an abstract class
  • create and implement an interface

abstract class

Abstract classes are base classes from which other classes may be derived. They may not be instantiated directly.

Unlike an interface, an abstract class may contain implementation details for its members.

Methods within an abstract class that are marked as abstract do not contain an implementation and must be implemented in derived classes.

For example, to create an abstract class:

abstract class A {
constructor(private _name: string) {}
abstract describe(): void get name(): string { return this._name; } set name(newName: string) { this._name = newName; }}

To extend an abstract class:

class B extends A {
constructor(public desc: string) {
super("B");
}

describe() { return this.desc; }
}

interface

TypeScript’s interface is very powerful. It defines the types of properties of an object. It is widely used in real-world project. For example, when the front-end receives a json, it will turn the json into an object. We use interface to define the type of the object’s properties.

In the section “object”, I defined Text type. Now, I use interface to redo it.

interface Text { id: number, description: string }

Both two methods works. But why do we use interface in real-world project ? Because the interface can do more than that.

Interface can have optional properties. For example, we have a text without id. The interface can be created as followed:

interface Text { id?: number, description: string }

It’s very common when we create a new text. Because id is not existed on server-side when it is just create at front-end.

Interface can have readonly properties. Usually, we don’t want the ID of text changed by the user. The interface can be set:

interface Text { readonly id?: number, description: string }

Interface can add indexable types. When we receive the information like title, author, date, etc. These aren’t presented in Text interface. We can used indexable types.

interface Text { 
readonly id?: number,
description: string,
[propName: string]: any,
}

It adds the flexibility to the interface, but loses the security. It may increase the chance of writing bugs. It’s better to define all the properties.

Interface can be extended by the class. It helps define the attributes’ types and the methods’ types of class.

Interface can be extended by another interface. It’s usually used by generic, which is another powerful tools in TypeScript, presented in the next section.

generic

The components we created should not only have well-defined and consistent APIs, but are also reusable. To make that happen, we need generic.

Generic type can be used in the function. It makes the function reusable.

For example, a function is used by both component A and component B. Component A passes a string to this function, while component B passes a number. Of course, we can use any or the union type string|number as the type of the parameter. But, the better practice is using generic:

function fn<T>(arg: T): T { return arg; }// Component A
fn<string>("something");
// Component B
fn<number>(1);

Generic keeps both the flexibility and security. It not only makes fn take any kind of the parameter, but also, ensures the parameter passed in the fn has the type we want.

Generic type can be used in the class. It makes the class reusable. It’s widely used in creating the components.

class A<T> { 
item: T;
getItemName() { return this.item.name; }
}

Now, the component A can take anything as its item. But, the function getItemName won’t work because TypeScript doesn’t know item has name property. To fix this, we need to use interface.

interface Item { name: string; }class A<T extends Item> { 
item: T;
getItemName() { return this.item.name; }
}

The generic extends the Item interface. Now, TypeScript knows item has name .

Conclusion

TypeScript improves the security of the codes. It helps the developers make sure what kind of the variable they use. Meanwhile, TypeScript gives the flexibility to developers, too. For example, the interface and the generic let the codes reusable.

The problem is how to balance the security and flexibility. The bad practice may lose the advantage of TypeScript. For example, if we use any everywhere, we lose the security. If we don’t use any or generic type, the codes will be hard to reuse.

No tutorial can give us the best methods. Practice makes perfect. Just start to use TypeScript, and find you only way.

Bonus

There is a great tool that help you use TypeScript in a JavaScript project. check it out.

--

--

Jijie Liu
The Startup

Developer in Paris, interested in building small cool stuffs