TypeScript Type Assertion 'as': Mastering Type Safety in Your Codebase

March 30, 24

Explore the power of TypeScript's type assertion to ensure robust type safety within your projects. Enhance code readability and maintainability effortlessly.

TypeScript Type Assertion 'as': Mastering Type Safety in Your Codebase - cover

Imagine having a magic wand that lets you tell TypeScript, "Hey, I know what I'm doing here!" That's essentially what type assertion is all about. It's your ticket to overriding TypeScript's guesses about variable types and asserting your dominance over data types.

Type assertion in TypeScript isn't rocket science, but it does have its own secret handshake. Get ready to decode the angle brackets <type> and the trusty as keyword as we uncover the syntax behind type assertion magic.

Ever wanted to tell TypeScript, "Trust me, it's a string!"? With type assertion, you can do just that! We'll start with the basics and learn how to assert our way through simple data types like a pro. We'll also cover when to use and not use type assertion as this can be harmful to your code - breaching data integrity and type safety.

First of all,

Why use type assertions?

TypeScript is known for its strong type system, which helps catch errors early and enhances code maintainability. However, there are scenarios where TypeScript's type inference might fall short or where developers have more knowledge about the types than TypeScript can deduce on its own. Example of such are document.getElementById, using third part y libraries, when using legacy javascript code, etc.

I like the example from typescript docs [ref]

const element = document.getElementById('main_canvas');
// ^? Element | null
// which doesn't clarify what the element could be
const element = document.getElementById('main_canvas') as HTMLCanvasElement;
// OR
const element = <HTMLCanvasElement>document.getElementById('main_canvas')

In this case you can use type assertion to better specify the element type as HTMLCanvasElement. Syntactically both as and <type> does the same job - asserting the type to something else.

Type Conversion

Note: Type Assertion doesn't do type conversion for you, it is just to override or tell typescript compiler to treat one type as other, it doesn't guarantee any type safety whatsoever, that's what I hate about it.

Assume this scenario, where you are type asserting an object to a string and then try to access a string method on it.

const apple = {} as string;
// yes, this is allowed
apple.replaceAll('seed', 'diamond')

With this unsafe type assertion, typescript would allow you to access replaceAll string method, but will actually lead to this error TypeError: x.replaceAll is not a function , trust me, I've seen this happening in real product code.

Type Guards

Let's look at a different example -

interface Animal {}

class Dog implements Animal {
bark() {

class Cat implements Animal {
meow() {

function makeSound(animal: Animal) {
(animal as Dog).bark();

makeSound(new Dog()); // 'bark'
makeSound(new Cat()); // TypeError: animal.bark is not a function

Even though typescript didn't complain in any ways here, the second call with Cat, errored with bark is not a function. This is because bark was not a method available with Cat. In these cases, rather than using the type assertion directly, consider using type guards - to narrow down the type and better scope the type.

Let's modify the makeSound function a little bit.

function makeSound(animal: Animal) {
if (animal instanceof Dog) {
// ^? Dog
} else if (animal instanceof Cat) {
// ^? Cat

Here, by checking the animal instanceOf with Dog and Cat, we are able to narrow down the types for them, and also better allow typescript to throw errors when something is not accessible.

Another tool you can use to type guard is typeof.

Ending point here: Use as very wisely, don't just try to bypass any typescript error you get, try to solve it with type guards, make javascript more safe, Happy Coding!