TypeScript

  1. Types
    1. Number Type
      1. Integer Checking
    2. String Type
    3. Boolean Type
  2. Type Inference
  3. Object Types
  4. Array Types
    1. Homogenous Arrays
    2. Heterogenous Arrays
  5. Tuple Types
  6. Enums
  7. Union Types
  8. Type Aliasing
  9. Return Types
    1. The Void Type
  10. Functions as Types

This chapter covers notes on TypeScript. What is TypeScript? It's a superset of JavaScript that provides some useful functionalities absent in vanilla JavaScript. These functionalities include various forms of syntactic sugar and, most importantly, type-checking.

As a JavaScript superset, everything we write in JavaScript can be written in TypeScript. But, browser cannot execute TypeScript. The TypeScript code must be transpiled to JavaScript first to affect changes.

Typechecking is TypeScript's most attractive feature. Consider the following example:

function add(number1, number2) {
	return number1 + number2;
}

All this function does is add two numbers.

const result = add(1, 2);
console.log(result);
3

As it stands, the function above can take a variety of arguments. In particular, strings:

const result = add("1", "2");
console.log(result);
12

This is likely not the behavior we intended. We could solve this problem by introducing a guard against strings, throwing an error if string arguments are passed. And while that is a perfectly fine solution, it's a problem that's easily solved with type-checking. TypeScript solves that problem.

Types

TypeScript provides many different types. We'll start with the most basic types — the core types provided by vanilla JavaScript.

Number Type

JavaScript doesn't differentiate betweeen floats and integers. There's just one type called number. Values of type number include 1, 5.3, -10, infinity, -infinity, 0, and -0.

With TypeScript, we can use the number type to specify that a function only takes number arguments:

function add(number1: number, number2: number) {
	return number1 + number2;
}

Integer Checking

Although JavaScript doesn't provide an integer type, it does provide a method called Number.isInteger() which returns true if a number is an integer and false otherwise. For example:

const x = Number.isInteger(5);
console.log(x);
const y = Number.isInteger(5.2);
console.log(y);
true
false

String Type

Strings have the type string. In JavaScript, there are three ways to specify strings: "string" (using double-quotes), 'string' (single-quotes), and `string` (using backticks).

Just as we saw with the number type, we can specify parameters with the string type keyword:

function isEmptyString(str: string) {
	return str === "";
}

Boolean Type

The Boolean values true and false can be type-checked with the type boolean.

function Nand(a: boolean, b: boolean) {
	return !(a && b);
}

Type Inference

TypeScript provides a type-inference system. For example, TypeScript can infer all of the following:

const x = 5; // infers number
const y = true; // infers boolean
let n = ""; // infers string

For declared but uninitialized variables, it's considered best practice to indicate the variable's type upfront:

let x: number;
let y: boolean;
let n: string;

Object Types

Suppose we had the following JavaScript object:

const square = {
	width: 5,
	height: 5,
	name: "square1",
};

TypeScript infers square's type as:

{
	width: number;
	height: number;
	name: string;
}

This works for nested objects as well.

const polygon = {
	sideNames: ["a", "b", "c", "d"],
	dimensions: {
		length: 5,
		width: 5,
	},
	name: "polygon1",
};

The inferred type:

{
	sideNames: string[],
	dimensions: {
		length: number,
		width: number
	},
	name: string,
};

Array Types

Arrays can also have types. As we know, JavaScript arrays can be homogenous (all of the array's elements are of one type) or heterogenous (the array consists of elements of various types).

Homogenous Arrays

Say we had the following array:

const arr = ["a", "b", "c"];

TypeScript infers this array's type as:

arr: string[];

Heterogenous Arrays

Heterogenous arrays, or mixed arrays, are arrays of different types. For example:

const arr = ["a", 1, true];

Generally speaking, mixed arrays are not safe. They're difficult to think about and can lead to unexpected behavior. That said, we can we give these arrays the type any, a generic type:

arr: any[];

Tuple Types

Tuples are a data structure unique to TypeScript. They are not a part of vanilla JavaScript. Simply put, tuples are arrays of fixed length. Having fixed lengths is useful when we know that some datum should consist of a finite, ordered set of values. For example, the Cartesian coordinate takes the form (x,y).{(x,y).} With TypeScript, we can write:

cartesianCoordinate: [number, number];

Enums

Enums are a useful type found in various languages. They're what we should use when we know that a particular value can only be one of a finite set. For example, we might have data that can only be one of VOTER and NONVOTER. In plain JavaScript, we might specify these as global constants:

const VOTER = "voter";
const NONVOTER = "nonvoter";

This allows us to use the values VOTER or NONVOTER anywhere in our code.

const VOTER = "voter";
const NONVOTER = "nonvoter";

if (user.registration === VOTER) {
	user.castVote();
}

The problem with this approach is that we have to keep track of these constants. Not a huge problem if we only have a few such constants, but it can get unwieldy once we have several.

Fortunately, TypeScript makes this easy:

enum VoteStatus {
	VOTER,
	NONVOTER,
}

if (user.registration === VoteStatus.VOTER) {
	user.castVote();
}

As with other languages, by default, the enum values map to numbers. Thus, the values above are really:

enum VoteStatus {
	VOTER = 0,
	NONVOTER = 1,
}

Of course, we can assign custom values:

enum VoteStatus {
	VOTER = "voter",
	NONVOTER = "nonvoter",
}

Union Types

Union types allow us to specify "or" type data. For example, we might have a function that takes a color value argument. That value could be a string (for an HTML named color) or a number (perhaps some HEX value). We could specify the function's parameter as:

function color(colorValue: string | number) {
	if (typeof colorValue === "string") {
		// code to execute if the value's a string
	} else {
		// code to execute if the value's a number
	}
}

Type Aliasing

Some union types — e.g., number | string — are so common that it'd be cumbersome to write such types over and over again. Similar to languages like ML, TypeScript allows us to write type aliases:

type Color = number | string;

function color(colorValue: Color) {
	if (typeof colorValue === "string") {
		// code to execute if the value's a string
	} else {
		// code to execute if the value's a number
	}
}

Type aliases aren't limited to union types. We can use them for all the previous types we've seen. For example, we might want to specify a Cartesian coordinate as always having the type CartesianCoordinate:

type CartesianCoordinate = [number, number];

Return Types

Some languages require functions to have return types (e.g., Rust, Swift, C, C++). Having explicit return types for functions makes our code much more predictable and reason about.

For example, a function that adds two numbers should always return a number:

function add(a: number, b: number): number {
	return a + b;
}

Notice how we placed the type after the function's header. This is tells TypeScript that our function add should always return a number.

The Void Type

For functions that do not return values, we can use the void type, provided by TypeScript:

function printErrorCode(code: number): void {
	console.log(code);
}

Functions as Types

TypeScript allows us to write function types. We can think of the function type as outlining what the function should take and return:

const f: () => number;

The code above tells TypeScript that the functione f takes no parameters and returns a number. If the function f does have parameters, say, numbers, we can write:

const f: (a: number, b: number) => number;