TypeScript Essentials
ts-essentials is a comprehensive collection of advanced TypeScript utility types designed to enhance type safety and improve developer experience beyond the standard library. As of version 10.1.1, it provides a wide array of types like `Prettify`, `DeepReadonly`, `StrictOmit`, and robust path-based utilities for complex object transformations, such as `Paths` and `PathValue`. The library is actively maintained with frequent patch and minor releases, typically occurring every few weeks, addressing bug fixes and introducing new utility types. Key differentiators include stricter versions of built-in utility types (e.g., `StrictExclude`), deep transformation types like `DeepRequired` and `DeepMarkOptional`, and sophisticated path-based type manipulation. It requires `typescript>=4.5.0` as a peer dependency and mandates the `strictNullChecks` compiler option in `tsconfig.json` for optimal functionality and type correctness, ensuring a higher level of type strictness.
Common errors
-
Type instantiation is excessively deep and possibly infinite. (2589)
cause Using `PathValue` or `Paths` with an older TypeScript version, particularly below 4.2.0, which lacks optimizations for deep type calculations.fixUpgrade your TypeScript version to `4.2.0` or higher. The library officially requires `4.5.0` or higher for full functionality. -
Property 'someOptionalProperty' does not exist on type 'Required<MyType>'.
cause Attempting to assign an object that is missing a formerly optional property to a type transformed by `Required` or `DeepRequired`, especially when `strictNullChecks` is not enabled, leading to incorrect type inference.fixEnsure `strictNullChecks` is enabled in your `tsconfig.json`. Also, verify that the object being assigned indeed has all required properties as non-nullable. -
Argument of type '(...)' is not assignable to parameter of type 'never'.
cause Incorrectly attempting to use a stricter utility type like `StrictExclude` or `StrictOmit` with a union type that does not align with its strict exclusion rules, leading to unintended type narrowing.fixCarefully review the `UnionType` and `ExcludedMembers` parameters for `StrictExclude`, or `Type` and `Keys` for `StrictOmit`, ensuring they precisely match the desired exclusion logic. These strict types are less forgiving than their built-in counterparts.
Warnings
- breaking `ts-essentials` versions prior to v10.0.0 supported older TypeScript versions. Since v10.0.0, the minimum required TypeScript version is `^4.2.0` due to advanced type features like `PathValue` and `Paths`. From v10.0.0 onward, specifically for `Mark*` utility types, `typescript>=4.5` is required.
- gotcha The library explicitly requires `strictNullChecks` to be enabled in your `tsconfig.json`. Disabling this option can lead to unexpected type behaviors and diminish the strictness and correctness of the provided utility types.
- deprecated The `DictionaryValues` utility type has been deprecated since version 10.0.2. Users should migrate to the `ValueOf` utility type for equivalent functionality.
- breaking In v10.0.0, the generic constraint on the second type parameter of `DeepOmit` and `DeepPick` was removed, and new `StrictDeepOmit` and `StrictDeepPick` types were introduced with generic constraints. This changes how these types are used.
- gotcha To prevent excessively deep type instantiation, the `Paths` utility type now limits the depth of path generation to 7 by default. While this improves performance, it might truncate paths for extremely deeply nested objects.
Install
-
npm install ts-essentials -
yarn add ts-essentials -
pnpm add ts-essentials
Imports
- Prettify
import { Prettify } from 'ts-essentials' - DeepReadonly
import { DeepReadonly } from 'ts-essentials' - Paths
import { Paths } from 'ts-essentials' - StrictOmit
import { StrictOmit } from 'ts-essentials'
Quickstart
import { Prettify, DeepReadonly, StrictOmit, Paths, PathValue } from 'ts-essentials';
interface User {
id: string;
name: string;
email?: string;
address: {
street: string;
city: string;
zip: number;
coordinates?: [number, number];
};
preferences: {
theme: 'dark' | 'light';
notifications: boolean;
};
roles: ('admin' | 'editor' | 'viewer')[];
}
// Prettify: Flattens and makes types more readable in IDE tooltips
type PrettyUser = Prettify<User>;
// DeepReadonly: Makes all properties and nested properties readonly
type ImmutableUser = DeepReadonly<User>;
// ImmutableUser.address.street = 'New Street'; // Type Error: Cannot assign to 'street' because it is a read-only property.
// StrictOmit: Constructs a type by picking all properties from Type and then removing Keys.
// It is a stricter version of TypeScript's built-in Omit.
type UserWithoutSensitiveInfo = StrictOmit<User, 'email' | 'address.coordinates' | 'roles'>;
const newUser: UserWithoutSensitiveInfo = {
id: 'abc-123',
name: 'Jane Doe',
address: { street: 'Main St', city: 'Anytown', zip: 12345 },
preferences: { theme: 'dark', notifications: true }
// email: 'jane@example.com' // Type Error: Object literal may only specify known properties
};
// Paths: Generates a union of all possible string paths within an object type
type UserPathExamples = Paths<User>;
// UserPathExamples could include 'id' | 'address.city' | 'preferences.theme' | 'roles.0'
// PathValue: Retrieves the type of the value at a specific path
type AddressCityType = PathValue<User, 'address.city'>; // string
type FirstRoleType = PathValue<User, 'roles.0'>; // 'admin' | 'editor' | 'viewer'