“instanceof” and “typeof” Type Guards

— — —

typeof

Considering the following formatMoney function that accepts a string or a number :

function formatMoney(amount: string | number): string {

let value = amount; // value type is number or string

if (typeof amount === "string") {

value = parseInt(amount, 10); // amount type is string

}

return value + " $"; // value type is number

}

Let’s take a look at what TypeScript documentation says about

the typeof type guard:

These typeof type guards are recognised in two different forms:

typeof v === "typename" and typeof v !== "typename" , where "typename" must be "number" , "string" , "boolean" , or "symbol" .

While TypeScript won’t stop you from comparing to other strings, the language won’t recognise those expressions as type guards.

Okay, TypeScript recognize certain use of typeof as type guard, but what does it mean?

It means that when having a type guard:

TypeScript and JavaScript runtime are tied to the same behaviour.

Let’s take a look at:

if (typeof amount === "string") {

value = parseInt(amount, 10); // amount type is string

}

Inside the if statement, TypeScript will assume that amount cannot be anything else than a string , which is true also at the runtime thanks to typeof JavaScript operator.

However, when looking at:

function formatMoney(amount: string | number): string {

TypeScript will try to prevent you to call formatMoney with anything else than a string or a number , however, nothing prevents you to do:

formatMoney({ myObject: 1} as any)

The cool thing here is that the typeof amount === "string" JavaScript operator usage will prevent the parseInt to be called with an object.

— — —

instanceof

The instanceof operator is also a type guard recognized by TypeScript, however, this one applies to function constructor (aka classes).

Here’s how is defined the behavior of the instanceof type guard in the TypeScript definition: