TypeScript Essentials

Doug Schallmoser
4 min readMar 3, 2021

--

The TypeScript documentation is very good for learning and understanding how to use TypeScript. With this post I thought I would jot down some notes about basic TypeScript to act as a short and simple reference for myself, and hopefully it is useful to others just starting out with using TypeScript.

The basic TypeScript types are: string, number, boolean, array, tuple, enum, unknown, any, void, null and undefined, never, and object. Many of these are straightforward as they are primitive JavaScript data types. I will go over some of the others with a bit more detail.

TypeScript is a programming language developed and maintained by Microsoft

The Any Type

Declaring with the any type allows you to write code similar to JavaScript which means you lose type safety. If you find yourself doing this then you should ask yourself why you are even using TypeScript in the first place. Using any is a sort of escape clause. I believe it should only be used as a temporary solution until you can figure out the appropriate type.

const apple: any = 'green';

The Void Type

When void is declared, it means there is no type. This is especially useful when a function does some work but doesn’t return a value. Void also improves the clarity of code by knowing the return value on the first line of the function.

function log(msg): void {
console.log(msg)
}

Array Typing

If you want to type all elements of an array to the same type, you can do so in two different ways:

1. Literal syntax:

let favoriteFoods: string[] = ['sushi', 'pizza', 'steak']

2. Generic interface type:

let favoriteFoods: Array<string> = ['sushi', 'pizza', 'steak']

Alternatively, if you want to type elements of an array in which there are a fixed/known number of elements, you can use a tuple:

let human: [string, number, boolean];human = ['Doug', 33, true];

Order matters in a tuple as the string, number, and boolean types are associated with that particular index in the array.

Unions

Unions provide the ability for a parameter/object to accept multiple types instead of single type. You will find this being very practical when you manipulating strings and numbers.

let salary: string | number = '75000'
apple = 75000

Below, the myAnimal variable can either follow the Dog or Cat interface typing scheme.

interface Dog {
name: string,
barks: boolean,
walks: boolean
}
interface Cat {
name: string,
meows: boolean,
independent: boolean
}
const myAnimal: Dog | Cat = {
name: 'Rover',
meows: false,
independent: true
}

Type Declaring Objects

There are two types of declarations you can use to shape your object. They are Type and Interface.

type PostType = {
link: string,
title: string,
read: boolean
}
interface PostInterface {
link: string,
title: string,
read: boolean
}
const firstPost: PostType = {
link: 'http', title: 'First Post', read: true
}
const secondPost: PostInterface = {
link: 'http', title: 'Second Post', read: false
}

You can see above that Type and Interface are very similar. Type uses the assignment operator while Interface doesn’t. In general Interfaces are preferred for your declarations. Type does allow you introduce a name for any type (such as primitive types) since you are using the assignment operator, which you cannot do with Interface.

type PostType = number

In addition, interfaces are extendable meaning they can be declared with additional typing. Types are not.

interface PostInterface {
link: string,
title: string,
read: boolean
}
interface PostInterface {
likes: number
}

You can also make any keys optional by adding a question mark at the end of the key. If we make link optional, as shown below, the compiler won’t complain about the firstPost variable.

interface PostInterface {
link?: string,
title: string,
read: boolean
}
const firstPost: PostInterface = {
title: 'First Post', read: true
}

Defining Named Sets of Constants

Enums allow you to create a set of distinct cases for named constants. This is useful as part of your switch statement in a state management reducer.

export enum ActionType {
Add = 'ADD_ITEM',
Remove = 'REMOVE_ITEM',
}
function CartReducer(state, action): ApplicationState {
switch (action.type) {
case ActionType.Add:
return {}
case ActionType.Remove:
return {}
default:
return state
}
}

The string enum above allows you to give a readable/meaningful value when your code runs.

Partials

If you want to make all types in your type declared object optional, you can use a Partial.

In the example below we are utilizing the UserData interface to type the context. If our default value when creating the context is an empty object, TypeScript will tell us:

Argument of type ‘{}’ is not assignable to parameter of type ‘UserData’

But we can implement a Partial to make all types optional:

interface UserData {
price: string,
income: number,
credit: number
}
const LoanContext = React.createContext<Partial<UserData>>({});

Non-null Assertion Operator

The ! represents the non-null assertion operator. When integrated, ! lets the compiler know to not complain because you are explicitly telling the type checker that the variable cannot be null or undefined. In most cases it is not advisable to use this operator (and often considered dangerous) as you are essentially overwriting the reason for using TypeScript. But there are certainly edge cases where it is useful, such as the following example.

Below, we only invoke the changeTitle method if this.post exists. So in changeTitle, we attached the non-null assertion operator to this.post because this.post will never be null or undefined here.

post: Post | null = null;

init() {
if (!this.post) {
this.post = { title: 'My Blog Post' }
}
this.changeTitle();
}

changeTitle() {
this.title = this.post!.title;
}

--

--