DEV Community

Gustavo Gondim
Gustavo Gondim

Posted on

TypeScript Advanced Types: My Daily Essentials Now on NPM

The ts-advanced-types library is a collection of utility types designed to simplify and enhance TypeScript development. I started it four years ago to address common challenges such as excluding specific properties from objects, enforcing mutually exclusive type options, and defining tree-like data models, making your code more expressive and maintainable.

Built to streamline everyday TypeScript tasks, this library consolidates frequently used advanced types into a reusable package. By sharing these tools with the community, my goal is to help developers write cleaner, more reliable code and save time across projects.

Installation and setup

Setting up the ts-advanced-types library is straightforward. Since the project is not transpiled, it directly exposes all types and utilities through its index.ts file. This ensures a lightweight and hassle-free integration into your TypeScript project.

Steps to install:

1 Add the library to your project via npm or yarn:

npm install ts-advanced-types
# or
yarn add ts-advanced-types
Enter fullscreen mode Exit fullscreen mode

2 Import the required types or utilities directly from the package:

import { TypeXOR, Without } from 'ts-advanced-types';
Enter fullscreen mode Exit fullscreen mode

No additional configuration is needed—you’re ready to start using the library. This simplicity allows you to focus entirely on leveraging the provided tools to enhance your TypeScript workflows.

What's inside

The library includes a wide range of utility types and helpers that solve common TypeScript challenges. From enforcing stricter object constraints to creating mutually exclusive type options, each utility is designed to address specific use cases while improving code clarity and maintainability. These types are all ready to use and can seamlessly integrate into your existing projects, saving you time and effort

Utility types

  • Without<T, U> Remove all properties from T that are assignable to U
  • TypeXOR<T, U> XOR of two types

Basic types

  • Falsy JavaScript falsy types
  • PrimitiveValidIndexSignature JavaScript primitive types accepted as index signatures
  • Primitive JavaScript primitive non-falsy types
  • Complex JavaScript non-falsy types
  • FalsyOrLiteral JavaScript primitive types, including falsy values
  • Document<T = Complex> An object made of string keys and non-falsy values. To add new types to values, use the T type parameter.
  • JsonOrString A JSON, as a string or as a parsed object or array

Advanced types/classes

  • TreeItem<T> A generic tree
  • EmptyConstructorOf<T> A type that implements a constructor without arguments
  • ClonableType<T> A type that is clonable: it can be instantiated with a partial object

Utility functions

  • isFalsyOrSpaces(value) Check if a value is falsy or a string with only spaces, ignoring number 0
  • withoutProps(obj, ...props) Clones an object, optionally removing a list of properties
  • equals(a, b) Checks if two objects are equal using the equals method or strict equality
  • getMethods(obj) List all methods of an object and its prototypes

Contribute and share your feedback

The library is an evolving project, and contributions from the developer community are always welcome. If you have ideas for new utility types, improvements, or discover any issues, feel free to open a pull request or report an issue on the GitHub repository.

Your feedback is invaluable in shaping the library to better serve TypeScript developers. If you’ve used ts-advanced-types in your projects, I’d love to hear about your experience! Leave a comment on this post or share your thoughts directly on GitHub. Together, we can make TypeScript development even more efficient and enjoyable.

Top comments (3)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Hello. It is a good thing to hear that people are interested in TypeScript.

I checked out your code and it requires revision. Refer to this playground.

In this sample, x.b is now of type undefined when it was originally string:

Image description

As I understand Without, it is the same as TS' Omit, only Omit works as expected.

Then I don't understand TypeXOR. What is "an exclusive OR" of two types? This one I cannot infer. If you can explain, it would be appreciated. The fact that is defined using Without makes matters worse because it is a faulty type to start with.

The playground link seems to show a union of all properties of each of the typés, and when they coincide, the data types are unionized. Since I don't understand the type, I cannot rule this as correct or not.

Anyway, good idea. If you want to see some pretty cool tricks, including recursive ones, I recently re-wrote the TypeScript for wj-config. This is a hierarchical configuration package and its new TypeScript is powerful. You can read the TypeScript Wiki page.

Collapse
 
ggondim profile image
Gustavo Gondim

Hi @webjose! Thanks for your valuable comment.

I started writing these types 8 years ago, and I pushed them to GitHub for the first time 2 years ago. Since then, a lot has changed in TypeScript, including the introduction of utility types that weren't available back then (only around version 3.5 did we start using them).

I completely agree that Without is essentially an Omit. I will likely remove it from the library in the next version.

Regarding TypeXOR, I also agree that the documentation could use some improvement for better clarity. However, I've faced challenges in clearly explaining its definition.

For now, the best way I can explain it is through an old use case where I used it: an implementation signature where the single argument must be either one specific type or a completely different one.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

I see. In that case, and if you're serious about contributing to the TypeScript community like this, what you must do now is make a full upgrade to the latest TypeScript. Once you do that and remove what is no longer needed, proceed to thoroughly document the remaining types, ideally with examples and use cases.

Once you do that, you can think about adding "unit tests" for the types using tsd. This way you'll have a robust foundation that can be built upon.

Good luck!