All Things Typescript

All Things Typescript

Home
Notes
Chat
Unstacked Labs
Monthly Newsletter
Archive
About

Share this post

All Things Typescript
All Things Typescript
Avoid using Type Assertions in TypeScript
Copy link
Facebook
Email
Notes
More

Avoid using Type Assertions in TypeScript

In this issue, I will explain why you should avoid using Type Assertions in Typescript and techniques you can use to avoid them.

Maina Wycliffe's avatar
Maina Wycliffe
Oct 23, 2023
5

Share this post

All Things Typescript
All Things Typescript
Avoid using Type Assertions in TypeScript
Copy link
Facebook
Email
Notes
More
1
Share
Cross-post from All Things Typescript
Type Assertions are bad, but why? -
Maina Wycliffe

We have all been there, and we have come across the following error:

And we have been inclined to solve the above issue by asserting the type.

example(y as string)

So, why am I discouraging you to avoid doing this? Let me answer that question in this issue of All Things Typescript.

But first, what are Type Assertions?

Types assertion is a way of telling Typescript what the type of a variable is. This can be done either of two ways: using the as syntax or the angle bracket <Type> syntax, as shown below:

type Person = {
    firstname: string;
    lastname: string;
}

// using as syntax
const x : unknown = {};

// asserting it as Person using as syntax
const firstname = (x as Person).firstname;

// asserting it as Person using the angle brackets
const firstname = (<Person>x).firstname;

Type assertion allows us as developers to provide more information to Typescript about a variable type. This is a good way to go when we have more information about a variable Type than Typescript is able to infer based on the limited information available to it. For instance, dom elements:

const button = document.getElementById("btn");

The type of button above is HTMLElement, which is generic. But we know that the type should be HTMLButtonElement and we can use assertions to provide more information to Typescript, as shown below:

const button = document.getElementById("btn") as HTMLButtonElement | null;

As you can imagine, this is a very powerful feature and can come in handy as shown above. But with power comes great responsibility and I believe that assertion should be used sparingly and not the default option.

When we use type assertion we are basically telling the Typescript compiler that we know what the type is and it should trust us, i.e. we know what we are doing. The problem with this is that we prevent Typescript from helping us where it should and take on that responsibility ourselves.

In the above example, Typescript does not type-check whether the variable x has the property firstname we are accessing because we are asserting the type, which will definitely introduce a bug into our system.

Typescript does provide some safeguards and will warn you when you try to perform an unsafe type assertion, as shown below:

function example(x: string) {
    // do something 
}

let y: number | undefined;

example(y as string)

In the case above, Typescript will warn you against performing a type assertion that’s not structurally sound.

Conversion of type 'number | undefined' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

Type 'number' is not comparable to type 'string'.(2352)

Of course, if you are still determined, you can still override Typescript by first asserting it as unknown and then to string, as shown below:

example(y as unknown as string)

One other thing to keep in mind is that if you are asserting to any, you will completely disable type-checking for that variable usage. This is because the any type is assignable to any variable and can be assigned to the any variable. This means any is dangerous as it can be contagious, due to its ability to be assigned to any variable and vice versa.

What about Non-null Assertions?

Another common type of assertion is a non-null assertion. In this assertion, we use the ! operator after variable to tell the Typescript compiler that a variable isn't null.

function square(x: number) {
	return x * x;
}

const x : number | undefined;

const answer = square(x!);

This assertion should be used sparingly, especially if the null suggestion is coming from external API typing like environment variables, which are always typed as string | undefined. I have come across not-so-obvious bugs that were thrown in a completely different section of the code with a different error message because I allowed an undefined variable to be passed on. This happened because instead of handling the possibility of the environment variable being undefined, I decided that non-null assertion was the way to go.

So, what are the Alternatives?

Narrowing of Types

Type narrowing is the process of moving a less precise type to a more precise type. For instance, taking a variable of type any and moving it to string. There are various ways of achieving this, which I have covered previously here, but I will take a look at a few notable ones.

Type Guards: You can use Type Guards to narrow the types of a union, unknown, any, etc. to a specific type:

function doSomething(x: string | number) {
    if(typeof x === "string") {
    	// do somethign with the string
    } else {
    	// do something with the number
    }
}

Truthiness Narrowing: You can check if a variable is truthy i.e. not undefined or null before using it:

function doSomething(x?: string) {
	if(x) {
		// type of x is now string
	}
}

Building Custom Type Guards: Finally, you can create type guards that do an exhaustive type checking on an object before asserting its type:

function isRectangle(shape: unknown): shape is Rectangle {
  if ("width" in shape && "height" in shape) {
  	// this is a rectangle
  	return true; 
  }
  // it's not a rectangle
  return false;
}

Providing Default/Fallback Values

This mostly works with null and undefined values, but instead of asserting to a string to remove the possibility of it being undefined, you can provide a default value that automatically becomes a string. You can achieve this by using either null coalescing operator (??) or the or ( ||) operator.

// using the nullish coalescing operator
const API_URL = process.ENV.API_URL ?? "DEFAULT URL";

// using the OR (||) logical operator
const API_URL = process.ENV.API_URL || "DEFAULT URL";

We can also use Javascript Logical Assignment Operator to provide a default value:

let x : string | number;

// provide a default value if null or undefined
x ??= "Hello World"

// provide a default value if falsy
x ||= "Hello World"

Conclusion

In today’s issue, we learned that by using type assertions, we are limiting the ability of the Typescript compiler to do Type checking for us. This can lead to us having bugs in our system which Typescript was meant to prevent. To avoid using assertions, we covered a few techniques we can use such as Type narrowing and providing fallback values in the case of possibly undefined/null values.

Share

That’s it for this week, and here are a few more issues you might interested in:

Always Prefer Type with a Narrower Scope in Typescript

Always Prefer Type with a Narrower Scope in Typescript

Maina Wycliffe
·
July 18, 2023
Read full story
When is a variables' Type Never?

When is a variables' Type Never?

Maina Wycliffe
·
June 19, 2023
Read full story
The typeof and keyof operators - referencing variable types in Typescript

The typeof and keyof operators - referencing variable types in Typescript

Maina Wycliffe
·
March 27, 2023
Read full story
Narrowing Types in Typescript

Narrowing Types in Typescript

Maina Wycliffe
·
January 17, 2023
Read full story

Leave a comment

User's avatar
Join Maina Wycliffe’s subscriber chat
Available in the Substack app and on web
5

Share this post

All Things Typescript
All Things Typescript
Avoid using Type Assertions in TypeScript
Copy link
Facebook
Email
Notes
More
1
Share

No posts

© 2025 Maina Wycliffe
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share

Copy link
Facebook
Email
Notes
More