Skip to content

Understanding TypeScript's Powerful Type Assertions Through Practical Examples

Updated: at 02:12 PM

Understanding TypeScript’s Powerful Type Assertions Through Practical Examples

TypeScript, a statically typed superset of JavaScript, offers a myriad of features that can be harnessed to write robust and maintainable code. One such feature is TypeScript’s type assertion, which allows developers to specify the type of an object more specifically than its current type. In this blog post, we will take a deep dive into a practical use case of TypeScript’s type assertion - creating an object with dynamic keys whose values have a specific type. The syntax we will be focusing on is ({} as Record<keyof T, string>).

The Problem

Imagine you’re developing a web application that displays speaker information for a conference. Each speaker has properties like id, first, last, bio, and sessionId. The data is fetched from an API, but in cases where the speaker is not found, you want to return a default object with the same keys as a valid speaker but with empty strings as values.

The Basic Solution

A naive approach to solve this problem would be to manually create the default object by specifying each key and setting the value as an empty string:

const defaultSpeaker = {
id: "",
first: "",
last: "",
bio: "",
sessionId: ""
};

This solution is simple, but not very scalable. If the Speaker interface changes, for example by adding new properties, you will have to manually update the default object everywhere it’s used.

Leveraging TypeScript

To create a more maintainable and scalable solution, we can use TypeScript’s Record utility type along with keyof keyword.

Breaking Down the Syntax

Let’s dissect the syntax ({} as Record<keyof Speaker, string>):

  1. {} - This represents an empty JavaScript object.
  2. Record - A TypeScript utility type that creates an object type with specified keys and the same type of values.
  3. keyof - A TypeScript keyword that creates a union type of all the keys of a given type.
  4. as - A TypeScript keyword used for type assertions. It tells TypeScript to treat one type as if it were another type.

Combining the Elements

By combining these elements, Record<keyof Speaker, string> creates an object type where the keys are the keys of the Speaker interface and the values are of type string. The type assertion as Record<keyof Speaker, string> then tells TypeScript to treat the empty object {} as if it were of this new object type.

interface Speaker {
id: string;
first: string;
last: string;
bio: string;
sessionId: string;
}

const defaultSpeaker = {} as Record<keyof Speaker, string>;

Caveats and Runtime Reality

It’s crucial to understand that the above syntax doesn’t actually create properties on the object at runtime. The resulting object is still empty. It’s TypeScript’s type system that allows you to treat it as if it had these properties.

In scenarios where you need the properties to exist at runtime with default values, you will have to create them explicitly. However, if your code is prepared to handle an object without these properties (such as by using optional chaining), this syntax can provide a more maintainable and dynamic solution.

Conclusion

TypeScript offers powerful features that allow for writing dynamic and robust types. Through the use of type assertions, utility types, and keywords such as keyof, you can create complex types that adapt to changes in your codebase. It is important, however, to be cognizant of the distinction between compile-time types and runtime values.

Check out the ORM (Object Relational Mapper) PRISMA. The database access method I use in all my projects