🧰 The ultimate TypeScript toolbox for modern web

8 min read

typescriptjavascriptnode.jsdx... and 2 more

Modern code bases are complex and require a lot of attention to maintain and scale. TypeScript is a powerful tool that can help you write robust and maintainable code. However, TypeScript is not just a language; it is an key part of web development ecosystem consisting of loads of tools and libraries that can help you write better code faster.

Tools and libraries

@total-typescript/ts-reset

Basically ts-reset is an CSS reset, but for TypeScript. This excellent library created by Matt Pocock enhances typings of the built-in APIs, such as:

  • .json() in fetch calls and JSON.parse returns unknown instead of any
  • Array.prototype.includes and Array.prototype.indexOf are now easier to use with as const arrays
  • Array's .filter(Boolean) now correctly narrows the type to exclude falsy values.
  • Map's and Set's .has() methods now works with any key provided. Not just only with the union of all keys.
  • Array.isArray won't ever narrow the any[] type
  • sessionStorage and localStorage are now safer with unknown return type used

Using ts-reset

The usage and installation is pretty straightforward

pnpm install @total-typescript/ts-reset -D

then simply create a new file called reset.d.ts in your project and add the following line:

import "@total-typescript/ts-reset";

NOTE: Have in mind that ts-reset is intended to use only in application's code! It should not be used in libraries or packages that are intended to be consumed by other projects.

Read more about the ts-reset package on its official documentation site

typed-query-selector

Typed query selector is an solid layer on top of the native querySelector and querySelectorAll browser API methods that provides a way to use these functions in a TypeScript compliant manner without any runtime overhead.

This set of tools created by g-plane provides huge list of marvellous features, including:

  • the strict mode checker that will let you know if the query selector has invalid syntax! This is done by returing never from the bad selector:

    import "typed-query-selector/strict";
    const element = document.querySelector("div[test"); // return `never`
    

    this will most likely stop your TypeScript from compiling the code base, which is a great way to catch errors early on.

  • detecting the grouped types of selected elements:

    import "typed-query-selector";
    const elements = document.querySelectorAll("div, span"); // return `HTMLDivElement | HTMLSpanElement`
    
  • supporting complex selectors; pseudoclass, id, attribute, and even :is() with :where()! mixing between these is also supported

    import "typed-query-selector";
    
    document.querySelector("div.container"); // ==> HTMLDivElement
    document.querySelector("div#app"); // ==> HTMLDivElement
    document.querySelector("input[name=username]"); // ==> HTMLInputElement
    document.querySelector("input:first-child"); // ==> HTMLInputElement
    document.querySelector(":is(div#id, span.class[k=v])"); // ==> HTMLDivElement | HTMLSpanElement
    document.querySelector(":where(div#id, span.class[k=v])"); // ==> HTMLDivElement | HTMLSpanElement
    
  • exposing the internal type-level parser (no runtime overhead added) to the public, for building your own functionality:

    import type {
      ParseSelector,
      StrictlyParseSelector, // or use the strict parser
    } from "typed-query-selector/parser";
    
    type MyElement = ParseSelector<"form#login">;
    

Using typed-query-selector

The usage and installation is easier than it seems

pnpm install typed-query-selector -D

then, like ts-reset you may want to create a file called types.d.ts in your project and add the following line:

import "typed-query-selector";

... or you can add this to the reset.d.ts if you're using both libraries!

For more general information about typed-query-selector's features e.g. extending the parser with custom HTML elements, please visit the official README.md and don't forget to give a star to this amazing project!

remeda

Are you a fan of lodash or ramda but lack of robust typings made you not choose utilizing such tools in your project? remeda is a library that provides a set of functions that resembles lodash and ramda but with a strong focus on TypeScript.

remeda was created by by Łukasz Sentkiewicz and is maintained with help of community contributors!

Some of the core library features:

  • all utility functions are implemented in both data-first and data-last style, this means that you don't need to create a pipe() every time you want to do something without creating mess in your code. Sometimes you just want to call single function like isNullish() instead of doing ugly variable == null

  • robust documentation with examples and types for each function, so you can easily understand what the function does, how to use it and where to use it. check it out!

  • immutability. All utility functions are immutable and have no side effects.

  • strong focus on making 100% out of type inference. This means you don't need to annotate almost anything.

  • minimal implementation with support of tree shaking. This one is a big win for remeda and allows you to use only the functions you need without adding unnecessary code to your bundle, especially on the frontend

  • lazy evaluation. Many functions support lazy evaluation when used in a pipeline. It's only partially suported in lodash and not supported in ramda so its a huge win for remeda!

    // Get first 3 unique values
    const arr = [1, 2, 2, 3, 3, 4, 5, 6];
    
    const result = R.pipe(
      arr,                    // only four iterations instead of eight (array.length)
      R.map(x => {
        console.log('iterate', x);
        return x;
      }),
      R.uniq(),
      R.take(3)
    ); // => [1, 2, 3]
    
    /**
    * Console output:
    * iterate 1
    * iterate 2
    * iterate 2
    * iterate 3
    * /
    
  • indexed version of each iterable function.

    const arr = [10, 12, 13, 3];
    
    // filter even values
    R.filter(arr, (x) => x % 2 === 0); // => [10, 12]
    // filter even indexes
    R.filter.indexed(arr, (x, i) => i % 2 === 0); // => [10, 13]
    

Using remeda

Unlike the previous libraries, Remeda actually affects the runtime and is not type-level only library utility - so you don't want to install it as your devDependency.

pnpm install remeda

then import it in your code base as you would do with any other library:

import * as R from "remeda";
// or
import { map, filter, pipe /* any other utilities */ } from "remeda";

NOTE: You may want to inspect the remeda's bundle and track its size if you plan to use it e.g. in end-user browser. See pkg-size.dev/remeda

type-fest

type-fest is a most popular types toolkit avaialable. with approximately 110m weekly downloads, this library created by Sindre Sorhus made itself a must-have in every TypeScript project - by providing types that should have been built-in.

There are loads of features in type-fest and I recommend you to check it out yourself on the official GitHub repository's README.md

Using type-fest

Install the library

pnpm install type-fest -D

then import a feature you need in your code base:

import type { LiteralUnion } from "type-fest";
type FooOrBarOrString = LiteralUnion<"foo" | "bar", string>;

zod

zod's by colinhacks is absolutely amazing library that provides a way to define and validate data schemas in a type-safe manner. It's a go-to solution in strict TypeScript world, just like yup and joi libraries that are widely used but in the JavaScript ecosystem

This solution is so reliable that even frameworks are build on top of it! For instance the Astro's content collections or tRPC and many more..

Some of the core features of zod:

  • battle tested and widely used in production - it's a mature library that is used by many developers and companies, so you can be sure that it's reliable

  • no dependencies so the area of potential bugs occurring is minimized

  • supports asynchronous operations during the schema refinements and transforms

  • uncomplicated API that is easy to use and understand - you don't need to be a TypeScript expert to use zod

  • many built in validators beyond primitive values - e.g. the .ip() or .email(). no more searching for regex to validate such things on StackOverflow!

  • relatively small bundle size in comparison to other libraries - it's a great choice for frontend projects or fullstack projects

Using zod

pnpm install zod

then define your schema and parse the data:

import { z } from "zod";

const schema = z.object({
  name: z.string(),
  age: z.number(),
});

const data = {
  name: "John",
  age: 30,
};

const parsedData = schema.parse(data);
// parsedData is ensured to be { name: "John", age: 30 } or error will be thrown

Explore the official documentation and examples on the zod's GitHub repository


Ending speech

All of mentioned libraries / toolkits are licensed under the MIT license so they're safe to use both in hobby and commercial projects and what is most important - they're free.

If you find them useful, please consider giving a star to the particular repository, donating money to authors and maintainers or even better - contributing to these projects!

Did you find this article helpful?

Share it with the world!