How to Get Started With TypeScript

JavaScript is weakly typed by its nature. This means that data types are always inferred from the variable declarations. This makes the language really flexible, and easy to learn for new programmers who don’t want to worry about different data types. But there’s a downside to this flexibility.

This can cause unexpected errors in your applications that you can easily catch with TypeScript even in your IDE before compile time. Imagine you are working on a game and you have some scores to be displayed. The data is stored in a database on the server, which you request. You get it back as a number and based on the values of other DOM elements, you want to increment this number. So you get the innerText from the DOM element and add it to your score:

const score = 100;
const bonus = document.getElementById('bonus').innerText; // Returns "20" as a string

// Score will be "10020"
score += bonus;
Copied to clipboard!

This isn’t quite the behavior you were looking for, but no errors will be thrown as JavaScript silently converts the number into a string. This could have been easily avoided.

TypeScript — a superset of JavaScript — can turn your JavaScript files into strongly typed TypeScript files. And since any valid JavaScript file also works as a TypeScript file, the learning curve is really shallow. You can type your already existing JavaScript code, incrementally as you go, without having to worry about breaking anything.


Get Started With TypeScript

To get started with TypeScript, you can install it globally by running npm i -g typescript in your terminal. With that installed, you should be able to transpile TypeScript files, using the tsc command in your terminal. Create a new file called index.ts, and add the following line, then run tsc index.js in the directory where the file has been created:

const hello = '👋';
index.ts
Copied to clipboard!

You will see that TypeScript will generate an index.js file next to your TypeScript file with the following content:

var hello = '👋';
index.js
Copied to clipboard!

It changed the const keyword to var, so we can be sure that TypeScript is now set up and is working. This happens because it transpiles your code down to ES3 by default. Of course, this code has nothing to do with TypeScript so far, the const keyword is part of ES6. It just shows that TypeScript can also transpile your code down to a different version of JavaScript. You can target the version among other things with CLI flags. For example, to transpile to ES6, you would do:

tsc index.ts -t ES6
tsc index.ts -target ES6
Copied to clipboard!

Both of them will work, and you get back the same variable with the const keyword. Of course, it would be super tedious to always write out these flags into the terminal, so TypeScript provides a configuration file, where you can configure every aspect of the compiler.

Configuring TypeScript

For that, you’re going to need to have a tsconfig.json file at your project’s root. Here you can specify a compilerOptions node where you can set the target among many other things.

{
    "compilerOptions": {
        "target": "ESNext"
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
}
tsconfig.json
Copied to clipboard!

Here you also have the option to include or exclude certain files from transpiling with glob pattern support. For the full list of available compiler options, you can refer to the official docs.


Using TypeScript

Now that you have everything set up, let’s start using TypeScript. First, let’s see how you can define types for your variables. By default, variable types are inferred from the declarations. For example, if you have the following variable:

const number = 5;
typeof number // returns "number"

const number = '5';
typeof number // returns "string"
number.js
Copied to clipboard!

It will be inferred as a number. JavaScript automatically assigns a type to it explicitly. If you change it to a string, then the type of the variable will be a string as well. In order to ensure we are dealing with a number, we need to assign a type using a double colon, followed by a type:

const number: number = 5;
number.ts
Copied to clipboard!

If you transpile your file into JavaScript, you will notice you won’t get any additional code in your output. You will only have var number = 5;. TypeScript checks the types at compile time. If you change the value of the variable to a string now, you will get an error, and you won’t even be able to transpile your ts file.

Trying to assign a string to a number type.

Apart from the number type, you have many other types you can use. Some of the more commonly used that you need to be aware of are:

Tuples

You know most of these already from JavaScript, but there are a couple of other types we need to talk about. For example, a tuple is a fixed size array where you know the type of each element:

const tuple: [string, number] = ['0', 1];
tuple.ts
Copied to clipboard!

This way you won’t be able to add or remove elements from the array. Also if you are referencing one of the elements, you get the proper object methods. For example on tuple[0] you will get an error if you try to use toFixed as it is not a string, but a number. And when you are dealing with regular arrays, you have two ways to type them:

// Use the type of the element followed by []
const emojis: string[] = ['1️⃣', '2️⃣', '3️⃣'];

// Use the generic array type: Array<type>
const emojis: Array<string> = ['1️⃣', '2️⃣', '3️⃣'];
arrays.ts
Copied to clipboard!

Enums

Enums are another helpful addition to JavaScript. With enums, you can create a set of values with more meaningful names. Take the following as an example:

enum Direction {
    Up,
    Left,
    Down,
    Right
}
enum.ts
Copied to clipboard!

Here, each value is a numeric value, starting from 0. This means that Right will be equal to 3. If you transpile this down and look into the JavaScript file, you will see the following generated:

var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Left"] = 1] = "Left";
    Direction[Direction["Down"] = 2] = "Down";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
enum.js
Copied to clipboard!

You can access the values just like you would for any other object in JavaScript.

Direction.Up
Direction.Down
... and so on ...
Copied to clipboard!

You can also change the starting value by assigning a number to it, or if you prefer, you can assign a value for each of them to further improve readability.

// Starting from 1 instead of 0
enum Direction {
    Up = 1,
    Left,
    Down,
    Right
}

// Asigning a value to each of them for better clarity
enum Direction {
    Up = 1,
    Left = 2,
    Down = 3,
    Right = 4
}

// You can also use strings as values
enum Direction {
    Up = 'UP',
    Left = 'LEFT',
    Down = 'DOWN',
    Right = 'RIGHT'
}
enum.ts
Copied to clipboard!

Any

One of the best features of TypeScript is the any type. The any type means that your type can be anything. You either don’t know it upfront or you don’t care. You would use this type when you are dealing with 3rd party code, or you are using an API, where you don’t know the return type. It’s also comes really handy when you want to migrate a big project from JavaScript to TypeScript. You can opt-out of type checking certain variables if you need to deliver code changes in a strict time schedule.

let variable: any = "I'm a string";

variable = 5      // Maybe I'm a number
variable = false; // Or am I a boolean?
any.tsUsing any, you won't get any compile errorsUsing any, you won't get any compile errors
Copied to clipboard!

Custom Types

Apart from the built-in types of TypeScript, you can also define your own types. So far, we’ve seen how to make a variable typed. But what if a variable can take up multiple types? For this, you can use a pipe (|):

const easing: 'LINEAR' | 'EASE-IN' | number = 'EASE-OUT';
Copied to clipboard!

The above example would throw an error as the type can be either a string (one of LINEAR or EASE-IN) or a number. To outsource this type and reuse it elsewhere, you can use the type keyword to define it as a custom type:

type Easing = 'LINEAR' | 'EASE-IN' | 'EASE-OUT' | number;

const easing: Easing = 'EASE-OUT';
easing.ts
Copied to clipboard!

Now this won’t throw any errors as we can also use EASE-OUT. This especially comes useful when you are dealing with more complex objects:

type HealthBar = {
    max: number,
    segment: number
}

type Enemy = {
    health: HealthBar,
    name: string,
    damage: number,
    alive: boolean
}

const enemy: Enemy = { ... }
types.ts
Copied to clipboard!

Note that you can also nest different types into each other. And if you incorrectly define your variable, you also get helpful error messages on what went wrong, and how you should fix it.

Type error in typescript
TypeScript warning, I’m missing the segment node from health

But what if you want to omit some of the properties for other types of enemies? Luckily, you don’t need to create entirely new types, instead you can use optional properties with a question mark before the double colon:

type Enemy = {
    health: HealthBar,
    name: string,
    damage: number,
    alive: boolean,
    boss?: Boss
}
types.ts
Copied to clipboard!

Here the boss property is optional, meaning even if you don’t pass it to your objects, TypeScript will still compile.

Functions

Functions are a fundamental building block in JavaScript. We’ve talked about a couple of basic types so far from the list above, but we haven’t touched the void type yet. When you are dealing with functions, you will most probably see void a lot. The type void infers that a function has no return value. Take the following as an example:

const addClickEventListener = (e: Event): void => { ... }
Copied to clipboard!

Here you are specifying the type of the return value of the function, after the parentheses. Since there is no return value for an event listener, the void type is used. Just like we did previously with variables, you can also type the parameters.

const add = (a: number, b: number): number => a + b;
Copied to clipboard!

Here the function returns a number, and both of the parameters are also typed as numbers.

Interfaces

Another common data type you’re going to find in TypeScript is interfaces. Very similar to the type alias, but unlike them, you can’t use interfaces for primitives, only for objects.

// ✅ this works
type Easing = 'LINEAR' | 'EASE-IN' | 'EASE-OUT' | number;

// ❌ this doesn't
interface Easing = 'LINEAR' | 'EASE-IN' | 'EASE-OUT' | number;

// ✅ this is valid
interface Easing {
    type: 'LINEAR' | 'EASE-IN' | 'EASE-OUT' | number;
}
objects-vs-primitives.ts
Copied to clipboard!

Also, interfaces are always extensible, and multiple interfaces with the same name will be merged together. This is not something you can do with type aliases.

interface Easing {
    type: 'LINEAR' | 'EASE-IN' | 'EASE-OUT' | number;
}

interface Easing {
    timing: number
}
merging.ts
Copied to clipboard!

These two interfaces will be merged together into one that has both a type and a timing property. You cannot do this with types.

Multiple type aliases with the same name.
You will get an error if you try to redefine a type alias with the same name.

What you can do instead, is use an ampersand to extend a base type in the following way:

type Easing = {
    type: 'LINEAR' | 'EASE-IN' | 'EASE-OUT' | number;
}

type EasingWithTiming = Easing & {
    timing: number
}

// The same can be done with interfaces using the `extends` keyword
interface EasingWithTiming extends Easing {
    timing: number
}
extending.ts
Copied to clipboard!

If you go ahead and transpile your file now to JavaScript, you will notice that nothing is generated for interfaces or type aliases, the compiler only uses this to check validity at compile-time, so it won’t affect your performance and bundle size in any way.

Classes

Classes are another extension in TypeScript. ES6 also introduced the class keyword, but for example, it lacks modifiers such as the public, private or protected keywords.

class Widget {
    private isCollapsed: boolean;
    
    constructor(collapsedByDefault: boolean) {
        this.isCollapsed = collapsedByDefault;
    }

    getState(): boolean {
        return this.isCollapsed;
    }
}
class.ts
Copied to clipboard!

You may notice we have only defined a private modifier, but nothing for the constructor and the getState method. In TypeScript, each member is public by default, so you can omit them. Again, if we transpile this code, we can see what TypeScript generates for us. In this case, all the way down to ES3.

var Widget = /** @class */ (function () {
    function Widget(collapsedByDefault) {
        this.isCollapsed = collapsedByDefault;
    }
    Widget.prototype.getState = function () {
        return this.isCollapsed;
    };
    return Widget;
}());
generatedClass.js
Copied to clipboard!

Generics

Lastly, I wanted to talk a bit about generics. When building applications, you often have to think about how to create reusable components, that also have a well-defined API. These components should work on a variety of types, instead of only handling just a single one. That makes them so flexible. You might be thinking the simplest way to create a generic is by using the any type.

const fn = (param: any): any => param;
Copied to clipboard!

And while that is true, this function will accept any type as an argument and can return anything, in the meantime, you lose information about what type is passed and what type is returned. You can know that a number is passed to the function, but you can’t be sure that a number is returned as well. It can be anything. Instead, what you can do is use a type variable to identify what type is being passed to the function, and what type is returned:

function fn<T>(param: T): T {
    return param;
};
generic.ts
Copied to clipboard!

Here, T identifies the type. You can then call this function in two ways with a specific type:

fn<number>(10); // Passing the type argument
fn(10);         // let TypeScript automatically set the type of `T` based on the argument
The latter option is more commonly used
Copied to clipboard!

Conclusion

And now you know everything you need to know to get started with TypeScript. If you find yourself stuck while using it, I highly recommend checking out their official documentation, it should have all the necessary information you need.

Have you worked with TypeScript before? Let us know your thoughts about it in the comments down below! Thank you for reading through, happy coding!

Remove ads
Remove ads

📚 Get access to exclusive content

Want to get access to exclusive content? Support webtips with the price of a coffee to get access to tips, checklists, cheatsheets, and much more. ☕

Get access Support us
Remove ads Read more on
Remove ads
Remove ads
🎉 Thank you for subscribing to our newsletter. x This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.