I. Prepare index.html

For this step we will create ToDo list application, here is the code for index.html file:

index.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TypeScript ToDo</title>
</head>
<body>
    <h1>Ultimate ToDo List</h1>
    <h2>Tasks:</h2>
    <ul id="task-list"></ul>
    <h3>New task:</h3>
    <form>
        <label for="task-priority">Priority:</label>
        <input type="text" id="task-priority">
        <label for="task-title">Title:</label>
        <input type="text" id="task-title">
        <button id="btn-add">Add</button>
    </form>
    <script src="index.js"></script>
</body>
</html>

II. Create index.ts

Let’s create code on in index.ts to handle adding tasks to the list and showing them:

let tasks = [];
document.getElementById('btn-add').addEventListener('click', e => {
    e.preventDefault();
    const priority = document.getElementById('task-priority')['value']; 
    const title = document.getElementById('task-title')['value'];
    tasks.push({
        priority: priority,
        title: title
    });
    let domString = '';
    tasks.forEach(t => {
        domString += `<li>Priority: ${t.priority}, Title: ${t.title}</li>`;
    });
    document.getElementById('task-list').innerHTML = domString;
});

III. Add types

Actually, the code above is written in EcmaScript 2015, we didn’t use anything specific for TypeScript in it, so let`s add types to values received from HTML inputs:

let tasks = [];
document.getElementById('btn-add').addEventListener('click', e => {
    e.preventDefault();
    const priority: number = Number(document.getElementById('task-priority')['value']); 
    const title: string = String(document.getElementById('task-title')['value']);
    tasks.push({
        priority: priority,
        title: title
    });
    let domString = '';
    tasks.forEach(t => {
        domString += `<li>Priority: ${t.priority}, Title: ${t.title}</li>`;
    });
    document.getElementById('task-list').innerHTML = domString;
});

If we try to compile the code we will receive an error: it tells us that we we provide incorrect type.

In this case we need to do do type conversion.

TypeScript supports type conversions called type assertions.

There two kind of syntax for type assertions bracket notation and as syntax, they produce same results:

let priority: number = <number>document.getElementById('task-priority')['value'];
let priority: number = document.getElementById('task-priority')['value'] as number;

The issue is that this kind of type conversion occurs only at compile time, it actually doesn’t do anything at run time:

Type assertions are a way to tell the compiler “trust me, I know what I’m doing.” A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler. TypeScript assumes that you, the programmer, have performed any special checks that you need.

So to do actual conversion we need to do it JavaScript-style:

index.ts:

...
const priority: number = Number(document.getElementById('task-priority')['value']); 
const title: string = String(document.getElementById('task-title')['value']);
...                       

Note: Type any is very special - anything can be assigned to variable of this type as well as vice versa.

IV. Create interface

Interface helps us to ensure that array contains now exact data types that are expected. Let’s create interface Task.

index.ts:

interface Task {
    priority: number,
    title: string
}

let tasks: Task[] = [];
document.getElementById('btn-add').addEventListener('click', e => {
    e.preventDefault();
    const priority: number = Number(document.getElementById('task-priority')['value']); 
    const title: string = String(document.getElementById('task-title')['value']);
    tasks.push({
        priority: priority,
        title: title
    });
    let domString = '';
    tasks.forEach(t => {
        domString += `<li>Priority: ${t.priority}, Title: ${t.title}</li>`;
    });
    document.getElementById('task-list').innerHTML = domString;
});

V. Convert interface to a class

Let’s convert interface to class, it gives us more control on the each task:

class Task {
    private priority: number;
    private title: string;
    constructor(priority: number, title: string) {
        this.priority = priority;
        this.title = title;
    }
    toString(): string {
        return `Priority: ${this.priority}, Title: ${this.title}`;         
    }
}

let tasks: Task[] = [];
document.getElementById('btn-add').addEventListener('click', e => {
    e.preventDefault();
    const task = new Task(Number(document.getElementById('task-priority')['value']), 
                          String(document.getElementById('task-title')['value']));
    tasks.push(task);
    let domString = '';
    tasks.forEach(t => {
        domString += `<li>${t.toString()}</li>`;
    });
    document.getElementById('task-list').innerHTML = domString;
});

VI. Implement inheritance

Let’s see how inheritance works in TypeScript. We will create class HighPriorityTask for tasks with priority equal to 1 and also create factory that will produce right Task for us using static method:

class Task {
    private priority: number;
    private title: string;
    constructor(priority: number, title: string) {
        this.priority = priority;
        this.title = title;
    }
    toString(): string {
        return `Priority: ${this.priority}, Title: ${this.title}`;         
    }
}

class HighPriorityTask extends Task {
    toString(): string {
        return `<strong>${super.toString()}</strong>`
    }
}

class TaskFactory {
    static getTask(priority: number, title: string): Task {
        if (priority === 1) {
            return new HighPriorityTask(priority, title);
        } else {
            return new Task(priority, title);
        }
    } 
}

let tasks: Task[] = [];
document.getElementById('btn-add').addEventListener('click', e => {
    e.preventDefault();
    const task = TaskFactory.getTask(Number(document.getElementById('task-priority')['value']), 
                          String(document.getElementById('task-title')['value']));
    tasks.push(task);
    let domString = '';
    tasks.forEach(t => {
        domString += `<li>${t.toString()}</li>`;
    });
    document.getElementById('task-list').innerHTML = domString;
});

See source code for this step on GiHub