Step 8 – Type guards and type assertions in TypeScript

In TypeScript, managing different types of values can sometimes be tricky, especially when you’re not sure about a value’s type at runtime. This is where type guards and type assertions become useful. If you’re familiar with Java, think of type guards like using instanceof and instanceof in Java to check object types at runtime, and type assertions like casting in Java.

Type Guards

Type guards help you check the type of a value at runtime and handle it accordingly. They are like type checks in Java but applied at runtime.

1. typeof Operator

The typeof operator checks the type of a primitive value (like string, number, etc.). It’s similar to using instanceof in Java but for primitives.

Example:

function logLength(value: string | number) {
  if (typeof value === 'string') {
    console.log(value.length); // Output: 5
  } else {
    console.log(Math.abs(value)); // Output: 4
  }
}

logLength('Hello');
logLength(-4);

Java Comparison:

In Java, you might use instanceof to check types:

public void logLength(Object value) {
    if (value instanceof String) {
        System.out.println(((String) value).length());
    } else if (value instanceof Integer) {
        System.out.println(Math.abs((Integer) value));
    }
}

2. instanceof Operator

The instanceof operator checks if a value is an instance of a class or an interface.

Example:

class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

function greet(person: Person | string) {
  if (person instanceof Person) {
    console.log(`Hello, ${person.name}!`); // Output: Hello, Sarah!
  } else {
    console.log(`Hello, ${person}!`); // Output: Hello, John!
  }
}

greet('John');
greet(new Person('Sarah', 25));

Java Comparison:

In Java, instanceof is used similarly:

public void greet(Object person) {
    if (person instanceof Person) {
        Person p = (Person) person;
        System.out.println("Hello, " + p.getName() + "!");
    } else if (person instanceof String) {
        System.out.println("Hello, " + (String) person + "!");
    }
}

3. in Operator

The in operator checks if a property exists in an object. It helps identify the type based on its properties.

Example:

interface Square {
  kind: 'square';
  size: number;
}

interface Rectangle {
  kind: 'rectangle';
  width: number;
  height: number;
}

type Shape = Square | Rectangle;

function calculateArea(shape: Shape) {
  if ('size' in shape) {
    return shape.size * shape.size; // Output: 25
  } else {
    return shape.width * shape.height; // Output: 50
  }
}

console.log(calculateArea({ kind: 'square', size: 5 }));
console.log(calculateArea({ kind: 'rectangle', width: 5, height: 10 }));

Java Comparison:

In Java, this can be likened to checking if an object has certain properties or methods using reflection.

Type Assertions

Type assertions are used to tell TypeScript the type of a value when it cannot infer it. This is similar to type casting in Java but is a bit different because it doesn’t perform any runtime type checking.

1. as Keyword

The as keyword lets you specify the type of a value.

Example:

const value: any = 'Hello';
const length = (value as string).length;

console.log(length); // Output: 5

Java Comparison:

In Java, type casting is used similarly:

Object value = "Hello";
String str = (String) value;
int length = str.length();
System.out.println(length); // Output: 5

2. Angle-Bracket Syntax

You can also use the angle-bracket syntax for type assertions.

Example:

const value: any = 'Hello';
const length = (<string>value).length;

console.log(length); // Output: 5

Java Comparison:

This is equivalent to type casting with parentheses in Java.

Type Assertion vs. Type Coercion

Type assertions are not the same as type coercion. Type coercion is automatic type conversion by JavaScript, while type assertions are manual and do not change the value’s type at runtime.

Type Assertion Example:

const value: any = '5';
const numberValue = value as number;
const sum = numberValue + 2;

console.log(sum); // Output: 7

Type Coercion Example:

const result = '5' + 2;

console.log(result); // Output: '52'

Java Comparison:

In Java, type coercion is similar to how implicit type conversion works when adding integers to strings:

String result = "5" + 2; // Result is "52"
System.out.println(result); // Output: 52

In summary, TypeScript’s type guards help you check and handle different types at runtime, while type assertions let you specify a type when TypeScript can’t infer it. These features make working with dynamic types easier, similar to how Java uses type checks and casting.

Leave a Reply

Your email address will not be published. Required fields are marked *