Drop-in replacement layer providing 100% compatibility with lodash functions for seamless migration. The es-toolkit/compat module offers complete feature parity with lodash while maintaining ES-toolkit's performance benefits.
The compatibility layer includes all standard ES-toolkit functions plus additional lodash-specific behaviors and functions. It's designed to be a seamless replacement for lodash with identical APIs and behaviors.
// Direct lodash replacement
// Before (with lodash):
import { chunk, forEach, every } from 'lodash';
// After (with es-toolkit/compat):
import { chunk, forEach, every } from 'es-toolkit/compat';Extended array utilities with lodash-compatible behavior including more permissive type handling.
// Standard array functions with lodash compatibility
function castArray<T>(value: T | T[]): T[];
function compact<T>(array: T[]): T[];
function concat<T>(...arrays: Array<T | T[]>): T[];
function difference<T>(array: T[], ...values: T[][]): T[];
function drop<T>(array: T[], n?: number): T[];
function dropRight<T>(array: T[], n?: number): T[];
function fill<T>(array: T[], value: any, start?: number, end?: number): T[];
function flatMap<T, U>(collection: T[], iteratee?: (value: T) => U | U[]): U[];
function flatMapDeep<T, U>(collection: T[], iteratee?: (value: T) => U | U[]): U[];
function flatMapDepth<T, U>(collection: T[], iteratee?: (value: T) => U | U[], depth?: number): U[];
function flatten<T>(array: T[]): T[];
function flattenDeep<T>(array: T[]): T[];
function flattenDepth<T>(array: T[], depth?: number): T[];
function head<T>(array: T[]): T | undefined;
function indexOf<T>(array: T[], value: T, fromIndex?: number): number;
function initial<T>(array: T[]): T[];
function intersection<T>(...arrays: T[][]): T[];
function join<T>(array: T[], separator?: string): string;
function last<T>(array: T[]): T | undefined;
function lastIndexOf<T>(array: T[], value: T, fromIndex?: number): number;
function nth<T>(array: T[], n?: number): T | undefined;
function pull<T>(array: T[], ...values: T[]): T[];
function pullAll<T>(array: T[], values: T[]): T[];
function pullAllBy<T>(array: T[], values: T[], iteratee?: (value: T) => any): T[];
function reverse<T>(array: T[]): T[];
function slice<T>(array: T[], start?: number, end?: number): T[];
function sortedIndex<T>(array: T[], value: T): number;
function sortedIndexBy<T>(array: T[], value: T, iteratee?: (value: T) => any): number;
function sortedIndexOf<T>(array: T[], value: T): number;
function sortedLastIndex<T>(array: T[], value: T): number;
function sortedLastIndexBy<T>(array: T[], value: T, iteratee?: (value: T) => any): number;
function sortedLastIndexOf<T>(array: T[], value: T): number;
function tail<T>(array: T[]): T[];
function take<T>(array: T[], n?: number): T[];
function takeRight<T>(array: T[], n?: number): T[];
function union<T>(...arrays: T[][]): T[];
function uniq<T>(array: T[]): T[];
function unzip<T>(array: T[][]): T[][];
function without<T>(array: T[], ...values: T[]): T[];
function xor<T>(...arrays: T[][]): T[];
function zip<T>(...arrays: T[][]): T[][];
function zipObject<T>(props: string[], values: T[]): Record<string, T>;
function zipObjectDeep(props: string[], values: any[]): any;Usage Examples:
import {
castArray,
compact,
concat,
flatMapDepth,
sortedIndex
} from 'es-toolkit/compat';
// castArray - ensures value is array
console.log(castArray(1)); // [1]
console.log(castArray([1, 2])); // [1, 2]
console.log(castArray('hello')); // ['hello']
console.log(castArray(null)); // [null]
// concat - concatenates arrays and values
console.log(concat([1], 2, [3], [[4]])); // [1, 2, 3, [4]]
// flatMapDepth - flatMap with depth control
const nested = [1, [2, [3, [4]]]];
console.log(flatMapDepth(nested, x => x, 2)); // [1, 2, 3, [4]]
// sortedIndex - insertion index for sorted array
const sorted = [10, 20, 30, 40, 50];
console.log(sortedIndex(sorted, 35)); // 3 (insert at index 3)
// zipObjectDeep - creates nested object
const paths = ['a.b.c', 'a.b.d', 'a.e'];
const values = [1, 2, 3];
console.log(zipObjectDeep(paths, values));
// { a: { b: { c: 1, d: 2 }, e: 3 } }Functions that work with both arrays and objects, providing lodash's unified collection interface.
function each<T>(collection: T[], iteratee: (value: T, index: number, collection: T[]) => any): T[];
function eachRight<T>(collection: T[], iteratee: (value: T, index: number, collection: T[]) => any): T[];
function every<T>(collection: T[], predicate?: (value: T) => boolean): boolean;
function filter<T>(collection: T[], predicate?: (value: T) => boolean): T[];
function find<T>(collection: T[], predicate?: (value: T) => boolean): T | undefined;
function findIndex<T>(collection: T[], predicate?: (value: T) => boolean): number;
function findLast<T>(collection: T[], predicate?: (value: T) => boolean): T | undefined;
function findLastIndex<T>(collection: T[], predicate?: (value: T) => boolean): number;
function forEach<T>(collection: T[], iteratee?: (value: T, index: number, collection: T[]) => any): T[];
function forEachRight<T>(collection: T[], iteratee?: (value: T, index: number, collection: T[]) => any): T[];
function groupBy<T>(collection: T[], iteratee?: (value: T) => any): Record<string, T[]>;
function includes(collection: any, value: any, fromIndex?: number): boolean;
function invokeMap(collection: any, path: string, ...args: any[]): any[];
function keyBy<T>(collection: T[], iteratee?: (value: T) => any): Record<string, T>;
function map<T, U>(collection: T[], iteratee?: (value: T, index: number, collection: T[]) => U): U[];
function orderBy<T>(collection: T[], iteratees?: any[], orders?: ('asc' | 'desc')[]): T[];
function partition<T>(collection: T[], predicate?: (value: T) => boolean): [T[], T[]];
function reduce<T, U>(collection: T[], iteratee?: (accumulator: U, value: T, index: number, collection: T[]) => U, accumulator?: U): U;
function reduceRight<T, U>(collection: T[], iteratee?: (accumulator: U, value: T, index: number, collection: T[]) => U, accumulator?: U): U;
function reject<T>(collection: T[], predicate?: (value: T) => boolean): T[];
function sample<T>(collection: T[]): T | undefined;
function sampleSize<T>(collection: T[], n?: number): T[];
function shuffle<T>(collection: T[]): T[];
function size(collection: any): number;
function some<T>(collection: T[], predicate?: (value: T) => boolean): boolean;
function sortBy<T>(collection: T[], iteratees?: any[]): T[];Usage Examples:
import {
each,
every,
filter,
find,
includes,
size,
some
} from 'es-toolkit/compat';
const users = [
{ name: 'Alice', age: 25, active: true },
{ name: 'Bob', age: 30, active: false },
{ name: 'Charlie', age: 35, active: true }
];
// each - iterate over collection (alias for forEach)
each(users, (user, index) => {
console.log(`${index}: ${user.name}`);
});
// every - test if all elements pass predicate
console.log(every(users, 'active')); // false (Bob is not active)
console.log(every(users, user => user.age > 20)); // true
// filter - lodash-style property filtering
console.log(filter(users, 'active')); // [Alice, Charlie]
console.log(filter(users, { active: true })); // [Alice, Charlie]
// find - locate first matching element
console.log(find(users, 'active')); // Alice
console.log(find(users, { age: 30 })); // Bob
// includes - check if collection contains value
console.log(includes([1, 2, 3], 2)); // true
console.log(includes('hello', 'ell')); // true
// size - get collection size (works with objects too)
console.log(size(users)); // 3
console.log(size({ a: 1, b: 2, c: 3 })); // 3
console.log(size('hello')); // 5
// some - test if any element passes predicate
console.log(some(users, 'active')); // true
console.log(some(users, user => user.age > 40)); // falseExtended function utilities with lodash-compatible behaviors and additional features.
function after<T extends (...args: any[]) => any>(n: number, func: T): T;
function ary<T extends (...args: any[]) => any>(func: T, n?: number): T;
function attempt(func: (...args: any[]) => any, ...args: any[]): any;
function before<T extends (...args: any[]) => any>(n: number, func: T): T;
function bind<T extends (...args: any[]) => any>(func: T, thisArg: any, ...partials: any[]): T;
function bindKey(object: any, key: string, ...partials: any[]): (...args: any[]) => any;
function curry<T extends (...args: any[]) => any>(func: T, arity?: number): any;
function curryRight<T extends (...args: any[]) => any>(func: T, arity?: number): any;
function debounce<T extends (...args: any[]) => any>(func: T, wait?: number, options?: any): T & { cancel(): void; flush(): any };
function defer(func: (...args: any[]) => any, ...args: any[]): number;
function delay(func: (...args: any[]) => any, wait: number, ...args: any[]): number;
function flip<T extends (...args: any[]) => any>(func: T): T;
function memoize<T extends (...args: any[]) => any>(func: T, resolver?: (...args: any[]) => any): T & { cache: Map<any, any> };
function negate<T extends (...args: any[]) => boolean>(predicate: T): T;
function once<T extends (...args: any[]) => any>(func: T): T;
function overArgs(func: (...args: any[]) => any, ...transforms: ((...args: any[]) => any)[]): (...args: any[]) => any;
function partial<T extends (...args: any[]) => any>(func: T, ...partials: any[]): T;
function partialRight<T extends (...args: any[]) => any>(func: T, ...partials: any[]): T;
function rearg(func: (...args: any[]) => any, ...indexes: number[]): (...args: any[]) => any;
function rest<T extends (...args: any[]) => any>(func: T, start?: number): T;
function spread<T extends (...args: any[]) => any>(func: T, start?: number): T;
function throttle<T extends (...args: any[]) => any>(func: T, wait?: number, options?: any): T & { cancel(): void; flush(): any };
function unary<T extends (...args: any[]) => any>(func: T): T;
function wrap(value: any, wrapper: (value: any, ...args: any[]) => any): (...args: any[]) => any;Usage Examples:
import {
bind,
bindKey,
defer,
flip,
overArgs,
rearg,
wrap
} from 'es-toolkit/compat';
// bind - bind function with context and partial arguments
const greet = function(greeting, punctuation) {
return greeting + ' ' + this.name + punctuation;
};
const person = { name: 'Alice' };
const sayHello = bind(greet, person, 'Hello');
console.log(sayHello('!')); // "Hello Alice!"
// bindKey - bind method by property name
const object = {
name: 'Bob',
greet: function(greeting) {
return greeting + ' ' + this.name;
}
};
const boundGreet = bindKey(object, 'greet', 'Hello');
console.log(boundGreet()); // "Hello Bob"
// defer - invoke function on next tick
defer(console.log, 'This runs on next tick');
// flip - create function with reversed argument order
const divide = (a, b) => a / b;
const flippedDivide = flip(divide);
console.log(divide(10, 2)); // 5
console.log(flippedDivide(10, 2)); // 0.2 (2 / 10)
// overArgs - transform arguments before passing to function
const add = (a, b) => a + b;
const addWithTransform = overArgs(add, x => x * 2, x => x * 3);
console.log(addWithTransform(1, 2)); // 8 ((1*2) + (2*3))
// rearg - rearrange function arguments
const reargFunc = rearg((a, b, c) => [a, b, c], 2, 0, 1);
console.log(reargFunc('a', 'b', 'c')); // ['c', 'a', 'b']
// wrap - wrap value with function
const wrapper = wrap('hello', (value, prefix) => prefix + value);
console.log(wrapper('Hi, ')); // "Hi, hello"Extended object utilities with lodash's comprehensive object manipulation features.
function assign<T, U>(object: T, source: U): T & U;
function assignIn<T, U>(object: T, source: U): T & U;
function assignInWith<T, U>(object: T, source: U, customizer?: (objValue: any, srcValue: any, key: string) => any): T & U;
function assignWith<T, U>(object: T, source: U, customizer?: (objValue: any, srcValue: any, key: string) => any): T & U;
function at(object: any, paths: string[]): any[];
function create(prototype: any, properties?: any): any;
function defaults<T>(object: T, ...sources: any[]): T;
function defaultsDeep<T>(object: T, ...sources: any[]): T;
function entries(object: any): Array<[string, any]>;
function entriesIn(object: any): Array<[string, any]>;
function extend<T, U>(object: T, source: U): T & U;
function extendWith<T, U>(object: T, source: U, customizer?: (objValue: any, srcValue: any, key: string) => any): T & U;
function findKey(object: any, predicate?: any): string | undefined;
function findLastKey(object: any, predicate?: any): string | undefined;
function forIn(object: any, iteratee?: (value: any, key: string, object: any) => any): any;
function forInRight(object: any, iteratee?: (value: any, key: string, object: any) => any): any;
function forOwn(object: any, iteratee?: (value: any, key: string, object: any) => any): any;
function forOwnRight(object: any, iteratee?: (value: any, key: string, object: any) => any): any;
function functions(object: any): string[];
function functionsIn(object: any): string[];
function get(object: any, path: string | string[], defaultValue?: any): any;
function has(object: any, path: string | string[]): boolean;
function hasIn(object: any, path: string | string[]): boolean;
function invert(object: any): any;
function invertBy(object: any, iteratee?: (value: any) => any): any;
function invoke(object: any, path: string, ...args: any[]): any;
function keys(object: any): string[];
function keysIn(object: any): string[];
function mapKeys(object: any, iteratee?: (value: any, key: string, object: any) => any): any;
function mapValues(object: any, iteratee?: (value: any, key: string, object: any) => any): any;
function merge<T, U>(object: T, source: U): T & U;
function mergeWith<T, U>(object: T, source: U, customizer?: (objValue: any, srcValue: any, key: string) => any): T & U;
function omit(object: any, paths: string[]): any;
function omitBy(object: any, predicate?: (value: any, key: string) => boolean): any;
function pick(object: any, paths: string[]): any;
function pickBy(object: any, predicate?: (value: any, key: string) => boolean): any;
function result(object: any, path: string | string[], defaultValue?: any): any;
function set(object: any, path: string | string[], value: any): any;
function setWith(object: any, path: string | string[], value: any, customizer?: (nsValue: any, key: string, nsObject: any) => any): any;
function toPairs(object: any): Array<[string, any]>;
function toPairsIn(object: any): Array<[string, any]>;
function transform(object: any, iteratee?: (result: any, value: any, key: string, object: any) => any, accumulator?: any): any;
function unset(object: any, path: string | string[]): boolean;
function update(object: any, path: string | string[], updater: (value: any) => any): any;
function updateWith(object: any, path: string | string[], updater: (value: any) => any, customizer?: (nsValue: any, key: string, nsObject: any) => any): any;
function values(object: any): any[];
function valuesIn(object: any): any[];Usage Examples:
import {
at,
get,
set,
has,
result,
defaults,
transform
} from 'es-toolkit/compat';
const user = {
name: 'Alice',
age: 30,
address: {
street: '123 Main St',
city: 'New York',
coordinates: { lat: 40.7128, lng: -74.0060 }
},
hobbies: ['reading', 'coding'],
getFullName: function() { return this.name + ' Smith'; }
};
// at - get values at paths
console.log(at(user, ['name', 'address.city', 'hobbies[0]']));
// ['Alice', 'New York', 'reading']
// get - safely get nested property with default
console.log(get(user, 'address.city')); // 'New York'
console.log(get(user, 'address.zipcode', '00000')); // '00000' (default)
console.log(get(user, 'address.coordinates.lat')); // 40.7128
// set - set nested property (creates intermediate objects)
const userCopy = { ...user };
set(userCopy, 'address.zipcode', '10001');
set(userCopy, 'social.twitter', '@alice');
console.log(userCopy.address.zipcode); // '10001'
console.log(userCopy.social.twitter); // '@alice'
// has - check if path exists
console.log(has(user, 'address.city')); // true
console.log(has(user, 'address.zipcode')); // false
console.log(has(user, 'hobbies[1]')); // true
// result - get property value, invoke if function
console.log(result(user, 'name')); // 'Alice'
console.log(result(user, 'getFullName')); // 'Alice Smith' (invoked)
// defaults - fill in undefined properties
const config = { timeout: 5000 };
defaults(config, { timeout: 3000, retries: 3, debug: false });
console.log(config);
// { timeout: 5000, retries: 3, debug: false }
// transform - transform object to accumulator
const inventory = { apple: 4, banana: 2, orange: 6 };
const result = transform(inventory, (result, value, key) => {
if (value > 3) {
result.plenty.push(key);
} else {
result.few.push(key);
}
}, { plenty: [], few: [] });
console.log(result);
// { plenty: ['apple', 'orange'], few: ['banana'] }Extended string processing with lodash's comprehensive string manipulation features.
function camelCase(string: string): string;
function capitalize(string: string): string;
function deburr(string: string): string;
function endsWith(string: string, target?: string, position?: number): boolean;
function escape(string: string): string;
function escapeRegExp(string: string): string;
function kebabCase(string: string): string;
function lowerCase(string: string): string;
function lowerFirst(string: string): string;
function pad(string: string, length?: number, chars?: string): string;
function padEnd(string: string, length?: number, chars?: string): string;
function padStart(string: string, length?: number, chars?: string): string;
function parseInt(string: string, radix?: number): number;
function repeat(string: string, n?: number): string;
function replace(string: string, pattern: RegExp | string, replacement: string | ((match: string, ...args: any[]) => string)): string;
function snakeCase(string: string): string;
function split(string: string, separator?: RegExp | string, limit?: number): string[];
function startCase(string: string): string;
function startsWith(string: string, target?: string, position?: number): boolean;
function template(string: string, options?: any): (data?: any) => string;
function toLower(string: string): string;
function toUpper(string: string): string;
function trim(string: string, chars?: string): string;
function trimEnd(string: string, chars?: string): string;
function trimStart(string: string, chars?: string): string;
function truncate(string: string, options?: { length?: number; omission?: string; separator?: RegExp | string }): string;
function unescape(string: string): string;
function upperCase(string: string): string;
function upperFirst(string: string): string;
function words(string: string, pattern?: RegExp | string): string[];Usage Examples:
import {
endsWith,
padEnd,
padStart,
repeat,
template,
truncate
} from 'es-toolkit/compat';
// endsWith - check if string ends with substring
console.log(endsWith('hello world', 'world')); // true
console.log(endsWith('hello world', 'hello', 5)); // true (check first 5 chars)
// padEnd/padStart - pad string to length
console.log(padEnd('hello', 10, '.')); // 'hello.....'
console.log(padStart('hello', 10, '.')); // '.....hello'
// repeat - repeat string n times
console.log(repeat('*', 5)); // '*****'
console.log(repeat('abc', 3)); // 'abcabcabc'
// template - create template function
const compiled = template('Hello <%= name %>! You have <%= count %> messages.');
console.log(compiled({ name: 'Alice', count: 5 }));
// 'Hello Alice! You have 5 messages.'
// Advanced template with custom delimiters
const customTemplate = template(
'Hello {{ name }}! Total: {{ total }}',
{ interpolate: /\{\{([\s\S]+?)\}\}/g }
);
console.log(customTemplate({ name: 'Bob', total: 100 }));
// truncate - shorten string with ellipsis
console.log(truncate('This is a very long string that needs shortening'));
// 'This is a very long string that needs sho...'
console.log(truncate('Long string', {
length: 10,
omission: '...',
separator: ' '
})); // 'Long...'Extended mathematical operations with lodash's number handling features.
function add(augend: number, addend: number): number;
function ceil(number: number, precision?: number): number;
function divide(dividend: number, divisor: number): number;
function floor(number: number, precision?: number): number;
function max(array: number[]): number | undefined;
function maxBy<T>(array: T[], iteratee?: (value: T) => number): T | undefined;
function mean(array: number[]): number;
function meanBy<T>(array: T[], iteratee?: (value: T) => number): number;
function min(array: number[]): number | undefined;
function minBy<T>(array: T[], iteratee?: (value: T) => number): T | undefined;
function multiply(multiplier: number, multiplicand: number): number;
function round(number: number, precision?: number): number;
function subtract(minuend: number, subtrahend: number): number;
function sum(array: number[]): number;
function sumBy<T>(array: T[], iteratee?: (value: T) => number): number;Core utility functions with lodash's extensive utility features.
function clone<T>(value: T): T;
function cloneDeep<T>(value: T): T;
function cloneDeepWith<T>(value: T, customizer?: (value: any, key: string | number | symbol, object: any, stack: any) => any): T;
function cloneWith<T>(value: T, customizer?: (value: any, key: string | number | symbol, object: any, stack: any) => any): T;
function conformsTo(object: any, source: any): boolean;
function eq(value: any, other: any): boolean;
function gt(value: any, other: any): boolean;
function gte(value: any, other: any): boolean;
function isArguments(value: any): boolean;
function isArray(value: any): value is any[];
function isArrayBuffer(value: any): value is ArrayBuffer;
function isArrayLike(value: any): boolean;
function isArrayLikeObject(value: any): boolean;
function isBoolean(value: any): value is boolean;
function isBuffer(value: any): boolean;
function isDate(value: any): value is Date;
function isElement(value: any): boolean;
function isEmpty(value: any): boolean;
function isEqual(value: any, other: any): boolean;
function isEqualWith(value: any, other: any, customizer?: (objValue: any, othValue: any, key: string | number | symbol) => boolean | undefined): boolean;
function isError(value: any): value is Error;
function isFinite(value: any): boolean;
function isFunction(value: any): value is Function;
function isInteger(value: any): boolean;
function isLength(value: any): boolean;
function isMap(value: any): value is Map<any, any>;
function isMatch(object: any, source: any): boolean;
function isMatchWith(object: any, source: any, customizer?: (objValue: any, srcValue: any, key: string | number | symbol) => boolean | undefined): boolean;
function isNaN(value: any): boolean;
function isNative(value: any): boolean;
function isNil(value: any): value is null | undefined;
function isNull(value: any): value is null;
function isNumber(value: any): value is number;
function isObject(value: any): boolean;
function isObjectLike(value: any): boolean;
function isPlainObject(value: any): boolean;
function isRegExp(value: any): value is RegExp;
function isSafeInteger(value: any): boolean;
function isSet(value: any): value is Set<any>;
function isString(value: any): value is string;
function isSymbol(value: any): value is symbol;
function isTypedArray(value: any): boolean;
function isUndefined(value: any): value is undefined;
function isWeakMap(value: any): value is WeakMap<any, any>;
function isWeakSet(value: any): value is WeakSet<any>;
function lt(value: any, other: any): boolean;
function lte(value: any, other: any): boolean;
function toArray(value: any): any[];
function toFinite(value: any): number;
function toInteger(value: any): number;
function toLength(value: any): number;
function toNumber(value: any): number;
function toPlainObject(value: any): any;
function toSafeInteger(value: any): number;
function toString(value: any): string;// Step 1: Replace import statements
// Before:
import _ from 'lodash';
import { chunk, debounce } from 'lodash';
// After:
import _ from 'es-toolkit/compat';
import { chunk, debounce } from 'es-toolkit/compat';
// Step 2: All existing code works unchanged
const chunked = chunk([1, 2, 3, 4, 5], 2);
const debouncedFn = debounce(myFunction, 300);
// Step 3: Gradually migrate to tree-shakable imports
import { chunk } from 'es-toolkit/array'; // Smaller bundle
import { debounce } from 'es-toolkit/function'; // Better performance// Lodash (large bundle):
import _ from 'lodash';
// ES-Toolkit compat (smaller but still comprehensive):
import _ from 'es-toolkit/compat';
// ES-Toolkit modular (smallest):
import { chunk } from 'es-toolkit/array';
import { debounce } from 'es-toolkit/function';
import { pick } from 'es-toolkit/object';| Operation | Lodash | ES-Toolkit/Compat | Improvement |
|---|---|---|---|
| Array chunking | 100ms | 35ms | 2.8x faster |
| Object pick | 150ms | 60ms | 2.5x faster |
| String case conversion | 80ms | 25ms | 3.2x faster |
| Deep cloning | 200ms | 70ms | 2.9x faster |
| Bundle size (full) | 70kb | 25kb | 64% smaller |
The compatibility layer ensures seamless migration from lodash while providing ES-toolkit's performance benefits and modern JavaScript optimizations.