ES-Toolkit
ES-Toolkit is a modern, high-performance JavaScript utility library designed for both Node.js and browser environments, emphasizing a small bundle size and robust TypeScript type annotations. Currently at version 1.45.1, the library demonstrates an aggressive release cadence, with updates typically arriving monthly or bi-monthly, reflecting continuous development and refinement. Key differentiators include its focus on performance, minimal footprint, and comprehensive type definitions which make it an excellent choice for TypeScript projects. It offers a wide array of functions for array manipulation, object operations, asynchronous utilities, and more, often providing Lodash-like functionality with a modern, tree-shakable architecture. Recent updates have focused on refining type safety, enhancing compatibility with Lodash behaviors, and introducing async utility methods.
Common errors
-
TypeError: (0 , es_toolkit__WEBPACK_IMPORTED_MODULE_0__.someFunction) is not a function
cause Attempting to use CommonJS `require()` or incorrect named imports in an environment expecting ESM, or a specific utility was not correctly exported in a prior version.fixEnsure you are using `import { someFunction } from 'es-toolkit';` for ESM environments. Verify the specific function exists in your installed version. Prior to v1.45.0, some packages might have been missing from `publishConfig`, leading to module not found errors for specific utilities. -
Property 'x' does not exist on type 'T'. Property 'x' does not exist on type 'undefined'.
cause This error can occur in TypeScript, specifically for versions <1.45.0 where `sample` might have returned `undefined` in its type signature, but then was reverted in v1.45.1. Or, it indicates a general type mismatch where a function's return type no longer includes a type you're expecting.fixCheck the exact version of `es-toolkit` you are using. For `sample`, ensure you are on v1.45.1+ if you expect no `undefined` in the return type. Always add appropriate nullish checks or type guards when dealing with potentially optional return values. -
Argument of type 'T' is not assignable to parameter of type 'U'.
cause A common TypeScript error indicating that the types inferred or provided to an ES-Toolkit utility function do not match its expected parameters, often due to strict type checking or changes in the library's type definitions.fixReview the function signature in the ES-Toolkit documentation or your IDE's type hints. Ensure your input types align with the expected parameters. You might need to refine your own types, use type assertions (`as`), or provide explicit type arguments if the function is generic. -
SyntaxError: Cannot use import statement outside a module
cause Attempting to use ESM `import` syntax in a Node.js environment configured for CommonJS, or in an older browser environment without a module loader.fixFor Node.js, ensure your `package.json` has `"type": "module"` or use a `.mjs` file extension. For older environments, consider using a bundler (like Webpack, Rollup, Parcel) to transpile your code to a compatible format.
Warnings
- breaking The return type of the `sample` function was changed in v1.45.0 to include `undefined`, but subsequently reverted in v1.45.1. Users who adapted their TypeScript code to handle `undefined` in v1.45.0 might experience type errors or runtime issues after upgrading to v1.45.1 or later.
- breaking The `merge` function's behavior was enhanced in v1.43.0 to handle arrays and objects more consistently and to match Lodash's behavior with date values and array-like objects. This change could lead to different merging outcomes compared to previous versions if your application relied on the older, non-Lodash compatible behavior.
- gotcha Prior to v1.43.0, the `throttle` function had a bug where it behaved like `debounce`. If you were using `throttle` in affected versions, its behavior might have been significantly different from the expected throttling mechanism.
- breaking The `omit` function was fixed in v1.42.0 to prevent adding index properties to array-like objects. While a fix, this change in behavior could be considered breaking if your code implicitly relied on the previous, incorrect modification of array-like objects.
- gotcha The `defaultsDeep` function received a fix in v1.39.10 to properly handle deep merging of objects within arrays. Previous versions might have exhibited incorrect or unexpected merging behavior when dealing with nested objects inside array structures.
Install
-
npm install es-toolkit -
yarn add es-toolkit -
pnpm add es-toolkit
Imports
- cloneDeep
const { cloneDeep } = require('es-toolkit');import { cloneDeep } from 'es-toolkit'; - throttle
import throttle from 'es-toolkit/throttle';
import { throttle } from 'es-toolkit'; - mapAsync
import * as esToolkit from 'es-toolkit'; esToolkit.mapAsync(...);
import { mapAsync } from 'es-toolkit';
Quickstart
import {
cloneDeep,
isEmptyObject,
throttle,
mapAsync,
retry,
} from 'es-toolkit';
interface User {
id: number;
name: string;
data?: Record<string, any>;
}
const users: User[] = [
{ id: 1, name: 'Alice', data: { age: 30 } },
{ id: 2, name: 'Bob', data: {} },
{ id: 3, name: 'Charlie' },
];
// Example 1: Deep cloning objects
const clonedUsers = cloneDeep(users);
console.log('Cloned Users:', clonedUsers);
console.log('Are they the same object reference?', clonedUsers === users); // false
// Example 2: Checking for empty objects
const userWithEmptyData = users[1];
console.log(`User ${userWithEmptyData.name} has empty data:`, isEmptyObject(userWithEmptyData.data));
// Example 3: Throttling a function
let count = 0;
const throttledIncrement = throttle(() => {
count++;
console.log('Throttled increment called, count:', count);
}, 100);
throttledIncrement();
setTimeout(throttledIncrement, 50); // Will not trigger
setTimeout(throttledIncrement, 150); // Will trigger again
// Example 4: Asynchronous mapping
const fetchUserData = async (id: number) => {
await new Promise(resolve => setTimeout(resolve, 50 * id)); // Simulate async
return { id, status: 'fetched' };
};
(async () => {
const userStatuses = await mapAsync(users, async (user) => {
return fetchUserData(user.id);
});
console.log('User statuses:', userStatuses);
})();
// Example 5: Retrying a failing operation
let attempt = 0;
const flakyOperation = async () => {
attempt++;
if (attempt < 3) {
console.log(`Flaky operation attempt ${attempt}: Failing...`);
throw new Error('Transient error');
}
console.log(`Flaky operation attempt ${attempt}: Succeeded!`);
return 'Success';
};
(async () => {
try {
const result = await retry(flakyOperation, { retries: 5, delay: 100 });
console.log('Retry result:', result);
} catch (e) {
console.error('Retry failed:', (e as Error).message);
}
})();