A guide to using ts-reset for TypeScript

Typing in JavaScript has always been an issue for developers. Because of its dynamic typing nature, it is difficult for developers coming from strongly typed languages like C# or Java to adjust to using JavaScript. TypeScript was introduced to solve this problem, but there are still some desired features lacking.

One example is the JSON.parse() function. TypeScript infers that the result of this function is of the type any, which introduces some issues because it gives a false impression that the provided response is safe to work with. This could lead to unwanted bugs. A more expected approach would have been to return an unknown type instead, forcing further validation from the developer.

Enter ts-reset, a CSS reset button for TypeScript that aims to improve types for common JS APIs. In this tutorial, we’ll explore how to use and set up ts-reset for TypeScript applications.

We’ll cover the following:

What is ts-reset?

ts-reset is an open source package that provides a set of rules that modify TypeScript’s built-in typings. ts-reset helps improve TypeScript typing and makes it more consistent with user expectations. It also makes the code more readable and maintainable and avoids bugs caused by type errors. You can think of this package as a TypeScript version of css-reset, which is a list of rules that reset all the default browser styles, removing potential inconsistencies between different browsers.

Why use ts-reset?

The TypeScript type default for several built-in functions isn’t great. The following are two examples where the default TypeScript typings result in subtle bugs:

  1. .json (in fetch) and JSON.parse both return any
  2. .filter(Boolean) giving out falsy values

Introducing ts-reset helps resolve these problems by making the typings as expected:

  1. .json (in fetch) and JSON.parse both return unknown
  2. .filter(Boolean)

We’ll go into more detail about this in a later section. Before that, let’s look at how to set up the package in a project.

Setting up ts-reset in our project

Getting started with ts-reset is easy. The first step is to install the package:

npm i -D @total-typescript/ts-reset

Next, create a reset.d.ts file in your project with the following code:

// Do not add any other lines of code to this file!
import "@total-typescript/ts-reset";

Now you’re ready to get started! If you don’t want this global use and would prefer to only include it on a file basis, or even on a feature basis, you can opt to use the inline approach instead. To do this, simply add the specific helper you need at the top of the file:

// Makes JSON.parse return unknown
import "@total-typescript/ts-reset/json-parse";

//ts-reset now applies
const result = JSON.parse("{}"); // unknown

N.B., For these imports to work, you’ll need to ensure that the module is set to NodeNext or Node16 in tsconfig.json.

ts-reset use cases

Now, let’s look at some use cases for the ts-reset package by addressing the problems we listed earlier.

Make JSON.parse return unknown

Before ts-reset, JSON.parse would return any. This can cause nasty, subtle bugs because they disable type checking on the values they describe:

// BEFORE ts-reset
const result = JSON.parse({}); // any

After using ts-reset, the result of JSON.parse changes to unknown. We now have to either validate unknown to ensure it’s the correct type using a tool like Zod, or cast it with as:

// AFTER ts-reset
const result = JSON.parse("{}"); // unknown

Make .json() return unknown

Just like JSON.parse(), .json() returning any introduces unwanted any into your application code, which could also lead to nasty bugs:

// BEFORE ts-reset
fetch("http://blog.logrocket.com/")
  .then((res) => res.json())
  .then((json) => {
    console.log(json); // any
  });

By forcing res.json to return unknown, we are aware of the need to validate the results of fetch as we now distrust the result from the res.json() method:

// AFTER ts-reset
fetch("http://blog.logrocket.com/")
  .then((res) => res.json())
  .then((json) => {
    console.log(json); // unknown
  });

Make .filter(Boolean) filter out falsy values

The default behavior of .filter doesn’t behave as expected. Given a set of values in an array with an undefined inclusive value, applying a Boolean constructor as a filter method removes all falsy values in the array, leaving only non-falsy values. However, TypeScript still sees the types as (number | undefined)[], using the initial values of the array as opposed to using the newly filtered array result.

Take the code below for example:

// BEFORE ts-reset
const filteredArray = [1, 2, undefined].filter(Boolean); // (number | undefined)[]

After applying ts-reset, the filter method now behaves as expected. It acts like a type predicate on the array passed in and removes any false values from the array member:

// AFTER ts-reset
import "@total-typescript/ts-reset/filter-boolean";

const filteredArray = [1, 2, undefined].filter(Boolean); // number[]

Future compatibility issues

Because the ts-reset package doesn’t involve any configuration from the user end, it doesn’t have any compatibility issues. Note that ts-reset is designed to be used in application code, not library code. This is because each rule you include will make changes to the global scope, meaning that users importing your library will unknowingly be using ts-reset.

Conclusion

ts-reset is a great utility package that helps solve the typing issue in JavaScript. In this article, we learned how we can use ts-reset to enhance TypeScript default typings to make them more predictable and bug-safe. ts-reset helps our TypeScript types behave as expected in our code. I hope you have fun using ts-reset to create great TypeScript projects!

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

.


Source link