ts-essentials vs ts-toolbelt
Advanced TypeScript Utility Libraries for Type Manipulation
ts-essentialsts-toolbelt

Advanced TypeScript Utility Libraries for Type Manipulation

ts-essentials and ts-toolbelt are both powerful libraries designed to extend TypeScript's built-in type system with advanced utility types. ts-essentials focuses on providing a curated set of high-value, commonly needed types like DeepPartial, ValueOf, and MarkRequired that solve frequent pain points in enterprise application development. It prioritizes stability, readability, and ease of adoption. ts-toolbelt, by contrast, offers an exhaustive collection of over 300 utility types, covering complex scenarios involving lists, numbers, strings, and deep object manipulation. It acts as a comprehensive toolkit for developers who need to perform intricate type-level programming or build highly generic libraries where standard TypeScript utilities fall short.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
ts-essentials04,076263 kB173 months agoMIT
ts-toolbelt07,150-846 years agoApache-2.0

ts-essentials vs ts-toolbelt: Choosing the Right Type Utility Library

When TypeScript's built-in utility types like Partial, Pick, or Record aren't enough, developers often reach for community libraries. ts-essentials and ts-toolbelt are the two leading options, but they serve very different needs. One is a focused toolkit for daily engineering tasks, while the other is an exhaustive encyclopedia of type manipulation. Let's break down how they differ in practice.

🎯 Scope and Philosophy: Focused vs. Exhaustive

ts-essentials follows a "less is more" approach.

  • It provides a small, curated list of types that solve the most common real-world problems.
  • The goal is to make code readable and maintainable without adding unnecessary complexity.
  • It avoids obscure features that only 1% of developers will ever use.
// ts-essentials: Common, high-value types
import { DeepPartial, ValueOf } from 'ts-essentials';

// DeepPartial makes every nested property optional
type Config = DeepPartial<{ db: { host: string; port: number } }>;
// Result: { db?: { host?: string; port?: number } }

// ValueOf extracts the union of all values from an object
type Roles = ValueOf<{ admin: 'admin'; user: 'user' }>;
// Result: 'admin' | 'user'

ts-toolbelt aims to be the "standard library" for type-level programming.

  • It includes hundreds of types for lists, numbers, strings, objects, and even logical operations.
  • It supports complex operations like sorting tuples at compile-time or performing math on number types.
  • The trade-off is a steep learning curve and a much larger API surface to navigate.
// ts-toolbelt: Advanced, niche capabilities
import { List, Number } from 'ts-toolbelt';

// Sort a tuple of numbers at the type level
type Sorted = List.Sort<[3, 1, 2]>;
// Result: [1, 2, 3]

// Perform math operations on types
type Sum = Number.Add<5, 10>;
// Result: 15

πŸ› οΈ Object Manipulation: Depth and Flexibility

Both libraries excel at transforming object types, but they offer different levels of control.

ts-essentials provides straightforward wrappers for deep modifications.

  • Types like DeepPartial, DeepRequired, and MarkOptional are easy to read and use.
  • They handle nested structures reliably without requiring complex configuration.
  • Ideal for API responses, form data, or configuration objects where depth varies.
// ts-essentials: Simple deep modification
import { MarkRequired } from 'ts-essentials';

type User = { id?: string; name: string; email?: string };

// Make 'id' and 'email' required, leave 'name' as is
type CompleteUser = MarkRequired<User, 'id' | 'email'>;
// Result: { id: string; name: string; email: string }

ts-toolbelt offers granular control over every aspect of an object.

  • You can merge, pick, omit, or modify keys with extreme precision.
  • It supports operations on key types, value types, and even the order of properties.
  • Best for building highly generic libraries where types must be constructed dynamically.
// ts-toolbelt: Granular object construction
import { Object } from 'ts-toolbelt';

type User = { id: string; name: string; role: string };

// Merge two types with specific overwrite rules
type AdminUser = Object.Merge<User, { role: 'admin' }>;
// Result: { id: string; name: string; role: 'admin' }

// Pick keys matching a specific pattern
type StringFields = Object.Pick<User, string>; // Hypothetical pattern match

πŸ”’ Advanced Type Operations: Numbers, Strings, and Lists

This is where the two libraries diverge significantly.

ts-essentials does not focus on primitive manipulation.

  • It sticks to object and union/intersection transformations.
  • If you need to calculate lengths or manipulate strings at the type level, this library won't help.
  • This keeps the package lightweight and focused on its core mission.
// ts-essentials: No native support for type-level math
// You would need to implement custom logic or use another library
// There is no built-in Add<1, 2> or Length<string>

ts-toolbelt shines in this area with dedicated modules for primitives.

  • It includes robust tools for Number, String, List, and Boolean operations.
  • You can validate string formats, calculate tuple lengths, or perform logic gates on types.
  • Essential for validating complex input shapes or building type-safe DSLs.
// ts-toolbelt: Type-level string and list operations
import { String, List } from 'ts-toolbelt';

// Check if a string type ends with a specific suffix
type IsTsFile = String.EndsWith<'index.ts', '.ts'>;
// Result: true (as a type-level boolean)

// Get the length of a tuple
type Len = List.Length<[1, 2, 3]>;
// Result: 3

πŸ“š Learning Curve and Maintenance

ts-essentials is beginner-friendly and stable.

  • The documentation is concise, and types are named intuitively.
  • Because the API surface is small, breaking changes between TypeScript versions are rare.
  • New team members can pick it up quickly without needing a deep dive into type theory.
// ts-essentials: Intuitive naming
import { Exact } from 'ts-essentials';

// Ensures a type matches exactly, no extra keys
function process<T>(arg: Exact<T, typeof arg>) { /*...*/ }

ts-toolbelt requires a deeper understanding of type-level programming.

  • The sheer volume of types can be overwhelming for new users.
  • Advanced features may rely on specific TypeScript compiler behaviors that could change.
  • It is best suited for senior developers or library authors who need maximum power.
// ts-toolbelt: Complex abstractions
import { Any, All } from 'ts-toolbelt';

// Check if all types in a list extend a certain constraint
type Valid = All<[string, number], any>;
// Requires understanding of variadic tuples and conditional types

🀝 Similarities: Shared Ground

Despite their differences, both libraries share some common goals and features.

1. πŸ” Deep Recursion Support

  • Both offer ways to recursively transform nested objects.
  • Useful for handling deeply nested JSON structures or complex state trees.
// ts-essentials
import { DeepNullable } from 'ts-essentials';
type A = DeepNullable<{ a: { b: string } }>;

// ts-toolbelt
import { Object } from 'ts-toolbelt';
type B = Object.Optional<{ a: { b: string } }, 'deep'>;

2. 🧩 Compatibility with Modern TypeScript

  • Both actively maintain support for recent TypeScript versions.
  • They leverage modern features like variadic tuples and template literal types.
// Both work with template literals
// ts-essentials: Uses them internally for key manipulation
// ts-toolbelt: Exposes them for string parsing utilities

3. βœ… Zero Runtime Overhead

  • Both are purely type-level libraries.
  • They add no JavaScript code to your bundle, ensuring zero performance impact at runtime.
// Importing these types adds 0 bytes to your final JS bundle
import { DeepPartial } from 'ts-essentials';
import { List } from 'ts-toolbelt';

πŸ“Š Summary: Key Differences

Featurets-essentialsts-toolbelt
Philosophy🎯 Focused, common use cases🌍 Exhaustive, all-encompassing
API SizeπŸ“¦ Small (~20 types)πŸ“š Massive (300+ types)
Learning Curve🟒 Easy, intuitiveπŸ”΄ Steep, requires type theory
Primitive Ops❌ Not supportedβœ… Numbers, Strings, Booleans
Best For🏒 App development, teamsπŸ§ͺ Library authors, complex generics
MaintenanceπŸ›‘οΈ Stable, low riskβš™οΈ Powerful, higher complexity

πŸ’‘ The Big Picture

ts-essentials is like a Swiss Army knife πŸ‡¨πŸ‡­β€”it has the few tools you actually need every day, and they work perfectly. Choose it for standard application development where clarity and stability matter most. It solves the "I need DeepPartial again" problem without dragging in a massive dependency.

ts-toolbelt is like a fully equipped machine shop πŸ­β€”it has every tool imaginable, including some you didn't know existed. Choose it when you are building complex abstractions, validating intricate data shapes, or pushing the limits of what TypeScript can do at the type level.

Final Thought: For most frontend teams, ts-essentials will cover 95% of needs with less friction. Reserve ts-toolbelt for those specialized cases where you truly need to perform type-level magic that no other library can handle.

How to Choose: ts-essentials vs ts-toolbelt

  • ts-essentials:

    Choose ts-essentials if your team needs a reliable, stable set of utility types for everyday application development without the overhead of a massive dependency. It is ideal for projects that require common transformations like making nested objects partial or extracting specific property values, where code readability and long-term maintenance are priorities. This package is the best fit when you want to solve 90% of type manipulation problems with a well-documented, focused API that rarely breaks across TypeScript versions.

  • ts-toolbelt:

    Choose ts-toolbelt if you are building complex generic libraries, performing advanced type-level logic, or need specific utilities for manipulating tuples, numbers, or strings that do not exist in other packages. It is suitable for scenarios where you need an exhaustive toolbox and are comfortable navigating a vast API surface to find niche solutions. Opt for this when your type requirements go beyond standard object manipulation and demand deep, recursive, or mathematical type operations that standard TypeScript cannot handle natively.

README for ts-essentials

ts-essentials

ts-essentials

All essential TypeScript types in one place πŸ€™

Version Downloads Build status Telegram Software License

Install

npm install --save-dev ts-essentials

πŸ‘‰ We require typescript>=4.5. If you're looking for support for older TS versions, please have a look at the TypeScript dependency table

πŸ‘‰ As we really want types to be stricter, we require enabled strictNullChecks in your project

API

ts-essentials is a set of high-quality, useful TypeScript types that make writing type-safe code easier.

Basic

Utility types

  • AsyncOrSync<Type> - Constructs a type with Type or PromiseLike<Type>
  • AsyncOrSyncType<Type> - Unwraps AsyncOrSync type
  • Dictionary<Type, Keys?> - Constructs a required object type which property keys are Keys (string by default) and which property values are Type
  • Merge<Object1, Object2> - Constructs a type by picking all properties from Object1 and Object2. Property values from Object2 override property values from Object1 when property keys are the same
  • MergeN<Tuple> - Constructs a type by merging objects with type Merge in tuple Tuple recursively
  • Newable<ReturnType> - Constructs a class type with constructor which has return type ReturnType
  • OmitNeverProperties<Type> - Constructs a type by picking all properties from type Type, which values don't equal to never
  • OmitProperties<Type, Value> - Constructs a type by picking all properties from type Type and removing those properties which values equal to Value
  • Opaque<Type, Token> - Constructs a type which is a subset of Type with a specified unique token Token
  • PathValue<Type, Path> - Constructs a path value for type Type and path Path
  • Paths<Type> - Constructs a union type by picking all possible paths for type Type
  • PickProperties<Type, Value> - Constructs a type by picking all properties from type Type which values equal to Value
  • PublicInterface<Type> - Constructs a type by extracting only the public members of Type, producing a plain object-compatible interface
  • RequireAtLeastOne<Type, Keys?> - Constructs a type with at least one required key from Keys (keyof Type by default) and other keys from Type which are not part of Keys
  • RequireAtMostOne<Type, Keys?> - Constructs a type with at most one required key from Keys (keyof Type by default) and other keys from Type which are not part of Keys
  • SafeDictionary<Type, Keys?> - Constructs an optional object type which property keys are Keys (string by default) and which property values are Type
  • UnionToIntersection<Union> - Constructs a intersection type from union type Union
  • ValueOf<Type> - Constructs a type for type Type and equals to a primitive for primitives, array elements for arrays, function return type for functions or object property values for objects
  • XOR<Type1, Type2, Type3?, ..., Type50?> - Construct a type which is assignable to either type Type1, Type2 but not both. Starting in ts-essentials@10, it supports up to 50 generic types.

Mark wrapper types

  • MarkOptional<Type, Keys> - Constructs a type by picking all properties from type Type where properties Keys are set as optional, meaning they aren't required
  • MarkReadonly<Type, Keys> - Constructs a type by picking all properties from type Type where properties Keys are set to readonly, meaning they cannot be reassigned
  • MarkRequired<Type, Keys> - Constructs a type by picking all properties from type Type where properties Keys are set as required
  • MarkWritable<Type, Keys> - Constructs a type by picking all properties from type Type where properties Keys remove readonly modifier, meaning they can be reassigned

Deep wrapper types

  • Buildable<Type> - Constructs a type by combining DeepPartial and DeepWritable, meaning all properties from type Type are recursively set as non-readonly and optional, meaning they can be reassigned and aren't required
  • DeepMarkOptional<Type, KeyPathUnion> - Constructs a type by picking all properties from type Type where properties by paths KeyPathUnion are set as optional. To mark properties optional on one level, use MarkOptional<Type, Keys>.
  • DeepMarkRequired<Type, KeyPathUnion> - Constructs a type by picking all properties from type Type where properties by paths KeyPathUnion are set as required. To mark properties required on one level, use MarkRequired<Type, Keys>.
  • DeepNonNullable<Type> - Constructs a type by picking all properties from type Type recursively and exclude null and undefined property values from all of them. To make properties non-nullable on one level, use NonNullable<Type>
  • DeepNullable<Type> - Constructs a type by picking all properties from type Type recursively and include null property values for all of them
  • DeepOmit<Type, Filter> - Constructs a type by picking all properties from type Type and removing properties which values are never or true in type Filter. If you'd like type Filter to be validated against a structure of Type, please use StrictDeepOmit<Type, Filter>.
  • DeepPartial<Type> - Constructs a type by picking all properties from type Type recursively and setting them as optional, meaning they aren't required. To make properties optional on one level, use Partial<Type>
  • DeepPick<Type, Filter> - Constructs a type by picking set of properties, which have property values never or true in type Filter, from type Type. If you'd like type Filter to be validated against a structure of Type, please use StrictDeepPick<Type, Filter>.
  • DeepReadonly<Type, OverrideDeepReadonlyOptions?> - Constructs a type by picking all properties from type Type recursively and setting readonly modifier, meaning they cannot be reassigned. To make properties readonly on one level, use Readonly<Type>
  • DeepRequired<Type> - Constructs a type by picking all properties from type Type recursively and setting as required. To make properties required on one level, use Required<Type>
  • DeepUndefinable<Type> - Constructs a type by picking all properties from type Type recursively and include undefined property values for all of them
  • DeepWritable<Type> - Constructs a type by picking all properties from type Type recursively and removing readonly modifier, meaning they can be reassigned. To make properties writable on one level, use Writable<Type>
  • StrictDeepOmit<Type, Filter> - Constructs a type by picking all properties from type Type and removing properties which values are never or true in type Filter. The type Filter is validated against a structure of Type.
  • StrictDeepPick<Type, Filter> - Constructs a type by picking set of properties, which have property values never or true in type Filter, from type Type. The type Filter is validated against a structure of Type.

Key types

  • OptionalKeys<Type> - Constructs a union type by picking all optional properties of object type Type
  • PickKeys<Type, Value> - Constructs a union type by picking all properties of object type Type which values are assignable to type Value
  • ReadonlyKeys<Type> - Constructs a union type by picking all readonly properties of object type Type, meaning their values cannot be reassigned
  • RequiredKeys<Type> - Constructs a union type by picking all required properties of object type Type
  • UnionKeys<UnionType> - Constructs a union type by picking all properties from all union members of UnionType
  • WritableKeys<Type> - Constructs a union type by picking all writable properties of object type Type, meaning their values can be reassigned

Type checkers

  • IsAny<Type> - Returns true when type Type is any. Otherwise returns false
  • IsExact<Type, Shape> - Returns Type when type Type and Shape are identical. Otherwise returns never
  • IsNever<Type> - Returns true when type Type is never. Otherwise returns false
  • IsUnknown<Type> - Returns true when type Type is unknown. Otherwise returns false
  • IsTuple<Type> - Returns Type when type Type is tuple. Otherwise returns never
  • NonEmptyObject<Object> - Returns Object when Object has at least one key. Otherwise returns never
  • NonUnion<Type> - Returns Type when Type is not an union. Otherwise returns never

Arrays and Tuples

Change case

Function types

Utility functions

⚠️ Make sure you add ts-essentials to your dependencies (npm install --save ts-essentials) to avoid runtime errors

Search

When one of utility types is known by a different name, kindly ask adding it here for the better search.

Declined

Built-in types

TypeScript provides several utility types to facilitate common type transformations. These utilities are available globally.

  • Awaited<Type> - This type is meant to model operations like await in async functions, or the .then() method on Promises - specifically, the way that they recursively unwrap Promises
  • Capitalize<StringType> - Converts the first character in the string to an uppercase equivalent
  • ConstructorParameters<Type> - Constructs a tuple or array type from the types of a constructor function type Type
  • Exclude<UnionType, ExcludedMembers> - Constructs a type by excluding from UnionType all union members that are assignable to ExcludedMembers
  • Extract<Type, Union> - Constructs a type by extracting from Type all union members that are assignable to Union
  • InstanceType<Type> - Constructs a type consisting of the instance type of a constructor function in Type
  • Lowercase<StringType> - Converts each character in the string to the lowercase equivalent
  • NonNullable<Type> - Constructs a type by excluding null and undefined from Type
  • NoInfer<Type> - Blocks inferences to the contained type. Other than blocking inferences, NoInfer<Type> is identical to Type
  • Omit<Type, Keys> - Constructs a type by picking all properties from Type and then removing Keys
  • OmitThisParameter<Type> - Removes the this parameter from Type. If Type has no explicitly declared this parameter, the result is simply Type. Otherwise, a new function type with no this parameter is created from Type. Generics are erased and only the last overload signature is propagated into the new function type.
  • Parameters<Type> - Constructs a tuple type from the types used in the parameters of a function type Type
  • Partial<Type> - Constructs a type with all properties of Type set to optional
  • Pick<Type, Keys> - Constructs a type by picking the set of properties Keys from Type
  • Readonly<Type> - Constructs a type with all properties of Type set to readonly, meaning the properties of the constructed type cannot be reassigned
  • Record<Keys, Type> - Constructs an object type whose property keys are Keys and whose property values are Type
  • Required<Type> - Constructs a type consisting of all properties of Type set to required
  • ReturnType<Type> - Constructs a type consisting of the return type of function type Type parameter
  • ThisParameterType<Type> - Extracts the type of the this parameter for a function type, or unknown if the function type has no this parameter
  • ThisType<Type> - This utility does not return a transformed type. Instead, it serves as a marker for a contextual this type. Note that the noImplicitThis flag must be enabled to use this utility
  • Uncapitalize<StringType> - Converts the first character in the string to a lowercase equivalent
  • Uppercase<StringType> - Converts each character in the string to the uppercase version

TypeScript dependency table

ts-essentialstypescript / type of dependency
^10.0.0^4.5.0 / peer optional
^9.4.0^4.1.0 / peer optional
^8.0.0^4.1.0 / peer
^5.0.0^3.7.0 / peer
^3.0.1^3.5.0 / peer
^1.0.1^3.2.2 / dev
^1.0.0^3.0.3 / dev

Limitations

Contributors

Special shout-out to active contributors:

And thanks goes to these wonderful people:

πŸ’» - contributions, i.e. links to commits by the user on this project

Contributions of any kind welcome! Read more