DEV Community

Dharan Ganesan
Dharan Ganesan

Posted on

Day 38: Assertions

What is a Type Assertion?

A type assertion tells to TypeScript, "Trust me, I know the type better than you do." It's like a developer's secret handshake, allowing you to override TypeScript's type inference and specify the type of a variable. They come in two flavors: the angle-bracket syntax and the as keyword.

Angle-Bracket Syntax

let someValue: any = "hello, world";
let strLength: number = (<string>someValue).length;
Enter fullscreen mode Exit fullscreen mode

In this example, we're telling TypeScript to treat someValue as a string temporarily so that we can access its length property. This syntax is more common in React projects or older JavaScript codebases.

The as Keyword

let someValue: any = "hello, world";
let strLength: number = (someValue as string).length;
Enter fullscreen mode Exit fullscreen mode

The as syntax is often preferred because it's more readable and less prone to confusion in complex code.

The Not Null Assertion

TypeScript also supports a special assertion called the "not null assertion," represented by !. This assertion tells TypeScript that a variable is not null or undefined. It can be helpful when you're sure a value exists but TypeScript is unsure.

function getLength(someValue: string | null | undefined) {
  return someValue!.length;
}
Enter fullscreen mode Exit fullscreen mode

Caution: Using the not null assertion when the value can actually be null or undefined can lead to runtime errors. It should be used sparingly and only when you're absolutely certain about the value's existence.

The as const Assertion

The as const assertion is a powerful tool for creating immutable objects and literal types.

Let's see it in action:

const colors = {
    red: "RED",
    blue: "BLUE",
} as const; // Assertion

type Color = keyof typeof colors; // Color is "red" | "blue"

const primaryColor: Color = "red"; // Valid
Enter fullscreen mode Exit fullscreen mode

Here, as const ensures that colors is treated as a read-only object, and TypeScript infers Color as a literal type.

🚧 When Not to Use Type Assertions

While type assertions are valuable, they come with risks. Using them carelessly can lead to runtime errors or negate TypeScript's type checking. Here are some scenarios to avoid:

  1. Ignoring Type Safety: Only use assertions when you are certain of a type. Blindly asserting types can hide bugs.

  2. Avoid the Any Type: Don't use assertions to escape the any type without good reason. It defeats TypeScript's purpose.

  3. Alternative Solutions: Consider alternative TypeScript features like type guards and narrowing types before resorting to assertions.

🤔 When to Use Type Assertions

Type assertions are most helpful in these situations:

  • Interacting with External Data: When dealing with data from external sources like APIs or user input, assertions can clarify types.

  • Working with Legacy Code: In older or untyped codebases, type assertions can bridge the gap between TypeScript and JavaScript.

  • Narrowing Types: When TypeScript can't narrow types automatically, assertions can provide hints to the type checker.

Examples

1. Working with Legacy Code

When you're dealing with untyped or loosely typed JavaScript code, type assertions can help you gradually introduce TypeScript without rewriting everything from scratch.

let legacyData: any = fetchDataFromLegacyAPI();
let typedData: DataType = legacyData as DataType;
Enter fullscreen mode Exit fullscreen mode

2. DOM Manipulation

Working with the Document Object Model (DOM) often involves type casting, as properties and methods can return generic objects.

const element = document.getElementById("myElement") as HTMLInputElement;
element.value = "Hello, TypeScript!";
Enter fullscreen mode Exit fullscreen mode

3. Testing

In unit tests, you might need to mock certain objects or values. Type assertions can be handy here to temporarily cast them to the expected type.

const mockedService = new MockedService() as MyService;
Enter fullscreen mode Exit fullscreen mode

4. Interfaces and Complex Types

When dealing with complex object structures, you might need to assert the types to navigate nested properties.

interface Person {
  name: string;
  address?: {
    street: string;
    city: string;
  };
}

const data: Person = {
  name: "John",
};

const city = (data.address as { city: string }).city;
Enter fullscreen mode Exit fullscreen mode

Top comments (0)