ts-essentials, ts-extras, and ts-toolbelt are utility libraries designed to extend TypeScript's built-in type system with advanced helper types. ts-essentials focuses on providing robust, battle-tested types for common edge cases like deep partials, exact objects, and safe Omit operations, prioritizing stability and ease of use. ts-extras offers a curated set of practical types and runtime helpers that bridge the gap between type-level logic and actual JavaScript execution, often solving specific pain points in modern frontend architectures. ts-toolbelt is a comprehensive, functional-programming-inspired toolkit containing hundreds of complex types for manipulating lists, strings, numbers, and types at a granular level, suitable for heavy metaprogramming.
When working with TypeScript in large-scale frontend applications, the built-in utility types like Partial, Pick, and Omit often aren't enough. You eventually hit walls where you need to make types deeply optional, enforce exact shapes to prevent excess properties, or manipulate types in ways that feel like writing code inside your types. This is where ts-essentials, ts-extras, and ts-toolbelt come in. While they all aim to supercharge your type system, they serve very different roles in an architecture.
The most important distinction lies in what each library tries to solve.
ts-essentials is the conservative choice. It focuses on fixing holes in TypeScript's standard library. Its goal is to provide types that "should have been built-in" but aren't, like DeepPartial or Exact. It prioritizes long-term stability and readability.
ts-extras sits in the middle. It provides practical types that solve specific, real-world problems developers face daily, often including runtime helpers alongside types. It is less about pure type manipulation and more about getting work done efficiently.
ts-toolbelt is the powerhouse. It treats types as data to be manipulated with functional programming principles. It contains hundreds of tools for list manipulation, string parsing, and number arithmetic at the type level. It is incredibly powerful but comes with significant complexity.
One of the most common needs is making every property in a nested object optional. Native Partial<T> only works on the top level.
ts-essentials provides DeepPartial. It is widely used, well-tested, and handles most standard cases reliably.
import { DeepPartial } from 'ts-essentials';
interface Config {
database: {
host: string;
port: number;
};
}
// All nested properties become optional
const myConfig: DeepPartial<Config> = {
database: {
host: "localhost"
// port is optional now
}
};
ts-extras also offers a DeepPartial type, often optimized for specific use cases found in modern frameworks, ensuring compatibility with complex generic patterns.
import { DeepPartial } from 'ts-extras';
interface State {
user: {
profile: {
name: string;
};
};
}
// Works similarly but may handle edge cases differently based on library version
const partialState: DeepPartial<State> = {
user: {
profile: {}
}
};
ts-toolbelt provides Deep.Partial, part of its namespaced architecture. It allows for extreme customization, such as stopping recursion at certain types, but requires more verbose syntax.
import { Deep } from 'ts-toolbelt';
interface Settings {
theme: {
colors: {
primary: string;
};
};
}
// Explicitly calls the Deep namespace
const partialSettings: Deep.Partial<Settings> = {
theme: {
colors: {
// primary is optional
}
}
};
TypeScript sometimes allows extra properties when passing objects to functions, which can cause bugs. An "Exact" type ensures you pass only the defined properties.
ts-essentials exports Exact specifically for this. It is a go-to solution for ensuring strict function arguments.
import { Exact } from 'ts-essentials';
function createUser(user: Exact<{ id: number; name: string }>) {
// ...
}
// Error: 'age' is not allowed
createUser({ id: 1, name: "Alice", age: 30 });
ts-extras provides similar functionality, often tailored to work seamlessly with common patterns in React props or API responses, ensuring type safety without excessive boilerplate.
import { Exact } from 'ts-extras';
function renderWidget(props: Exact<{ width: number; height: number }>) {
// ...
}
// Error: Extra property 'color' rejected
renderWidget({ width: 100, height: 50, color: "red" });
ts-toolbelt approaches this via its Any or Union checks, but does not have a single exported Exact type in the same simple form. You would typically construct this using lower-level primitives like Has or Keys, which increases complexity for a simple task.
// ts-toolbelt does not have a direct 'Exact' export like the others.
// You would need to build a custom constraint using lower-level tools,
// making it overkill for this specific scenario.
This is where the libraries diverge sharply. If you need to manipulate strings, numbers, or lists at the type level, ts-toolbelt is in a league of its own.
ts-toolbelt excels here. It can split strings, calculate numbers, and merge lists entirely at compile time.
import { String, Number } from 'ts-toolbelt';
// Split a string literal type
type Parts = String.Split<"hello-world", "-">;
// Result: ["hello", "world"]
// Add numbers at type level
type Sum = Number.Add<2, 3>;
// Result: 5
ts-essentials does not attempt these kinds of operations. It sticks to structural changes (Partial, Required, Pick) rather than content manipulation.
// ts-essentials has no equivalent for string splitting or math.
// Attempting this would require custom, complex type definitions.
ts-extras also avoids deep metaprogramming. It focuses on types that help with data structure shaping rather than type-level computation.
// ts-extras does not provide type-level arithmetic or string parsing.
// It remains focused on practical application shapes.
As of the latest checks, none of these packages are officially deprecated. However, their maintenance models differ.
ts-essentials is highly stable. Updates are infrequent because the core problems it solves (DeepPartial, Exact) don't change often. It is safe for long-term enterprise projects.ts-extras is actively maintained with updates that align with modern TypeScript releases. It is a solid choice for new projects needing practical helpers.ts-toolbelt is powerful but complex. While not deprecated, its heavy reliance on recursive types can sometimes cause performance issues in newer TypeScript versions or lead to longer compile times. Use it with caution in large codebases.| Feature | ts-essentials | ts-extras | ts-toolbelt |
|---|---|---|---|
| Primary Goal | Fill standard library gaps | Practical, real-world helpers | Advanced type metaprogramming |
| Complexity | Low | Medium | Very High |
| Deep Partial | ✅ DeepPartial | ✅ DeepPartial | ✅ Deep.Partial |
| Exact Types | ✅ Exact | ✅ Exact | ❌ (Manual construction) |
| Type Math/Strings | ❌ | ❌ | ✅ Extensive support |
| Best For | Standard Apps | Modern Frameworks | Library Authors |
Choosing the right library depends entirely on the complexity of your type needs.
If you are building a standard React application, a dashboard, or an enterprise platform, ts-essentials is your best friend. It gives you the superpowers you actually need—like making nested configs optional or enforcing strict props—without dragging in unnecessary complexity. It is the "batteries-included" approach for types.
If you find yourself needing slightly more specialized tools that bridge runtime and compile-time logic, or if you want a curated set of extras that feel modern and opinionated, ts-extras is a strong contender. It strikes a balance between utility and simplicity.
Reserve ts-toolbelt for when you are writing a library that others will use, or if you are building a domain-specific language (DSL) where types need to perform logic. For 95% of frontend development tasks, it is simply too much tool for the job. Using it for simple DeepPartial needs is like using a industrial crane to hang a picture frame—it works, but it's not the right tool.
Final Recommendation: Start with ts-essentials. It covers the vast majority of real-world scenarios with the least friction. Only reach for ts-toolbelt if you hit a wall that the other two cannot solve.
Choose ts-essentials when you need reliable, standard utility types for everyday development tasks like making all properties optional recursively or enforcing exact object shapes. It is the best fit for teams that want to avoid the complexity of maintaining custom utility types while ensuring high compatibility across TypeScript versions without risking build breaks from overly experimental features.
Choose ts-extras if your project requires a blend of advanced type utilities and lightweight runtime helpers that solve specific, recurring problems in React or Node.js environments. This package is ideal when you want practical, opinionated solutions that are more specialized than ts-essentials but less overwhelming and abstract than the massive collection found in ts-toolbelt.
Choose ts-toolbelt only when you are building complex type-level libraries, DSLs, or frameworks that require intense metaprogramming capabilities like type-level arithmetic, string manipulation, or deep conditional logic. Avoid this for standard application development, as its steep learning curve and heavy compile-time cost are unnecessary for typical business logic and can slow down your editor experience.
All essential TypeScript types in one place 🤙
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
ts-essentials is a set of high-quality, useful TypeScript types that make writing type-safe code easier.
Builtin - Matches primitive, function, date, error or regular expressionJsonArray - Matches any JSON arrayJsonObject - Matches any JSON objectJsonPrimitive - Matches any
JSON primitive valueJsonValue - Matches any JSON valueKeyofBase -
keyofStringsOnly-tolerant analogue for PropertyKeyPrettify<Type> - flattens type and makes it more readable on the hover in your IDEPrimitive - Matches any
primitive valueStrictExclude<UnionType, ExcludedMembers> - Constructs a type by excluding from UnionType
all union members that are assignable to ExcludedMembers. This is stricter version of
ExcludeStrictExtract<Type, Union> - Constructs a type by extracting from Type all union members
that are assignable to Union. This is stricter version of
ExtractStrictOmit<Type, Keys> - Constructs a type by picking all properties from Type and then
removing Keys. This is stricter version of
OmitWritable<Type> - Constructs a type with removed readonly for all properties of Type, meaning
the properties of the constructed type can be reassignedAsyncOrSync<Type> - Constructs a type with Type or PromiseLike<Type>AsyncOrSyncType<Type> - Unwraps AsyncOrSync typeDictionary<Type, Keys?> - Constructs a required object type which property keys are Keys
(string by default) and which property values are TypeMerge<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 sameMergeN<Tuple> - Constructs a type by merging objects with type Merge in tuple Tuple recursivelyNewable<ReturnType> - Constructs a class type with constructor which has return type ReturnTypeOmitNeverProperties<Type> - Constructs a type by picking all properties from type Type, which values don't
equal to neverOmitProperties<Type, Value> - Constructs a type by picking all properties from type Type
and removing those properties which values equal to ValueOpaque<Type, Token> - Constructs a type which is a subset of Type with a specified unique token
TokenPathValue<Type, Path> - Constructs a path value for type Type and path PathPaths<Type> - Constructs a union type by picking all possible paths for type TypePickProperties<Type, Value> - Constructs a type by picking all properties from type Type
which values equal to ValuePublicInterface<Type> - Constructs a type by extracting only the public members of Type, producing a plain object-compatible interfaceRequireAtLeastOne<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 KeysRequireAtMostOne<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 KeysSafeDictionary<Type, Keys?> - Constructs an optional object type which property keys are
Keys (string by default) and which property values are TypeUnionToIntersection<Union> - Constructs a intersection type from union type UnionValueOf<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 objectsXOR<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.MarkOptional<Type, Keys> - Constructs a type by picking all properties from type Type where
properties Keys are set as optional, meaning they aren't requiredMarkReadonly<Type, Keys> - Constructs a type by picking all properties from type Type where
properties Keys are set to readonly, meaning they cannot be reassignedMarkRequired<Type, Keys> - Constructs a type by picking all properties from type Type where
properties Keys are set as requiredMarkWritable<Type, Keys> - Constructs a type by picking all properties from type Type where
properties Keys remove readonly modifier, meaning they can be reassignedBuildable<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 requiredDeepMarkOptional<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 themDeepOmit<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 themDeepWritable<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.OptionalKeys<Type> - Constructs a union type by picking all optional properties of object type
TypePickKeys<Type, Value> - Constructs a union type by picking all properties of object type Type
which values are assignable to type ValueReadonlyKeys<Type> - Constructs a union type by picking all readonly properties of object
type Type, meaning their values cannot be reassignedRequiredKeys<Type> - Constructs a union type by picking all required properties of object type
TypeUnionKeys<UnionType> - Constructs a union type by picking all properties from all union members of UnionTypeWritableKeys<Type> - Constructs a union type by picking all writable properties of object type
Type, meaning their values can be reassignedIsAny<Type> - Returns true when type Type is any. Otherwise returns falseIsExact<Type, Shape> - Returns Type when type Type and Shape are identical. Otherwise returns
neverIsNever<Type> - Returns true when type Type is never. Otherwise returns falseIsUnknown<Type> - Returns true when type Type is unknown. Otherwise returns falseIsTuple<Type> - Returns Type when type Type is tuple. Otherwise returns neverNonEmptyObject<Object> - Returns Object when Object has at least one key. Otherwise
returns neverNonUnion<Type> - Returns Type when Type is not an union. Otherwise returns neverAnyArray<Type?> - Matches Array or ReadonlyArray (Type is any by default)AnyNonEmptyArray<Type> - Matches array with at least one element of type TypeArrayOrSingle<Type> - Matches Type or Type[]ElementOf<Type> - Constructs a type which equals to array element type for type TypeHead<Type> - Constructs a type which equals to first element in type TypeReadonlyArrayOrSingle - Matches Type or readonly Type[]Tail<Type> - Constructs a type which equals to elements but first one in type TypeTuple<Type?> - Matches type constraint for tuple with elements of type Type (any by default)CamelCase<Type> - Converts type Type to camel case (e.g. camelCase)DeepCamelCaseProperties<Type> - Constructs a type by picking all properties from
type Type recursively and converting all of them to camel caseAnyFunction<Args?, ReturnType?> - Matches function type with arguments type Args (any[] by
default) and return type ReturnType (any by default)PredicateFunction - Matches type constraint for type guard, meaning first argument is
used in return type and return type is
type predicatePredicateType<Type> - Constructs a type which equals to narrowed type in predicate function
Type⚠️ Make sure you add ts-essentials to your dependencies (npm install --save ts-essentials) to avoid runtime errors
new UnreachableCaseError(value) - Matches runtime class instance type that
helps check exhaustiveness for value. When value isn't never, it shows TypeScript errorassert(condition, message?) - Matches runtime function that helps assert condition. When
condition is falsy, it throws an error with Assertion Error: ${message} (message is
"no additional info provided" by default)createFactoryWithConstraint<Constraint>()(value) - Matches runtime
function, which validates that type of value matches Constraint without changing resulting type of value.
Ponyfill for
satisfies operatorisExact<Expected>()(actual) - Matches runtime function, which validates that type of
actual equals to Expected. Otherwise shows TypeScript errornoop(..._args) - Matches runtime function that does nothing with arguments _argsWhen one of utility types is known by a different name, kindly ask adding it here for the better search.
ArrayValues - ValueOf<Type>Branded - Opaque<Type, Token>ConditionalKeys - PickKeys<Type, Value>Except - StrictOmit<Type, Keys>Get - PathValue<Type, Path>Mutable - Writable<Type>Nominal - Opaque<Type, Token>Set*, e.g. SetOptional - Mark*, e.g. MarkReadonly<Type, Keys>Unwrap - Prettify<Type>ValueOf - DictionaryValuesArray.includes - Use ts-reset instead. See compromises in Array.includes as a type guardBoolean as a type guard in Array.filter - Use ts-reset instead.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 PromisesCapitalize<StringType> -
Converts the first character in the string to an uppercase equivalentConstructorParameters<Type> -
Constructs a tuple or array type from the types of a constructor function type TypeExclude<UnionType, ExcludedMembers> -
Constructs a type by excluding from UnionType all union members that are assignable to ExcludedMembersExtract<Type, Union> -
Constructs a type by extracting from Type all union members that are assignable to UnionInstanceType<Type> - Constructs
a type consisting of the instance type of a constructor function in TypeLowercase<StringType> -
Converts each character in the string to the lowercase equivalentNonNullable<Type> - Constructs a
type by excluding null and undefined from TypeNoInfer<Type> - Blocks inferences to the contained type. Other than blocking inferences, NoInfer<Type> is identical to TypeOmit<Type, Keys> - Constructs a
type by picking all properties from Type and then removing KeysOmitThisParameter<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 TypePartial<Type> - Constructs a type
with all properties of Type set to optionalPick<Type, Keys> - Constructs a
type by picking the set of properties Keys from TypeReadonly<Type> - Constructs a type
with all properties of Type set to readonly, meaning the properties of the constructed type cannot be reassignedRecord<Keys, Type> - Constructs
an object type whose property keys are Keys and whose property values are TypeRequired<Type> - Constructs a type
consisting of all properties of Type set to requiredReturnType<Type> - Constructs a
type consisting of the return type of function type Type parameterThisParameterType<Type> - Extracts the type of the this parameter for a function type, or unknown if the function type has no this parameterThisType<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 utilityUncapitalize<StringType> -
Converts the first character in the string to a lowercase equivalentUppercase<StringType> -
Converts each character in the string to the uppercase versionts-essentials | typescript / 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 |
extends Constraints on infer Type Variables as it's introduced in TypeScript 4.7, but currently ts-essentials supports versions below, e.g. TypeScript 4.5. Read more in https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#extends-constraints-on-infer-type-variablesSpecial 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