Although TypeScript is an extremely strong language, it mainly depends on types. Additionally, you could discover that you write more types than actual code at times. In this situation, you should look into the Utility types, which will enable you to write fewer types while maintaining the type safety of your code.
Let's start with a straightforward example. Assume that you have a list of events that the application produces along with a list of handlers for each of those events. So you could write something like this (but don't do it that way):
Then, then requirements changes, which often happens, and now you need to handle
beep action. You update the Action type, but might forget to update
handleAction function which will lead to a bug. However, with help of utility types, you can be protected from such type of failure:
Now, when new action will come, you will be automatically notified that you need to extend your handlers. If you accidentally remove some code from handlers, you will be notified as well. Great TypeScript feature!
You can do the same trick with objects:
This was done with the help of the
keyof keyword. It extracts keys from the interface or type and creates another type. Simplifying it may look like this:
This tip is very useful for the validation scenarios when you want to ensure that all properties of the object are handled.
If you want to know how to extract types from the array (or tuples), it's also easy, just don't forget to use
as const statement:
Another useful utility type, you might be already familiar with is
Partial<TModel> type. It is very handy when you are filling a domain model from untrusted resources or do some null/undefined behavior testing. Imagine that you are fetching big objects that might be partially filled and want to avoid
Cannot read property XXX of null type exception. In this case, you can use Partial type and TypeScript will automatically suggest you verify your data: