Contributing to es-toolkit
May 10, 2026 · View on GitHub
We welcome contribution from everyone in the community. All communications in this repository will be in English.
Every contributor to es-toolkit should adhere to our Code of Conduct. Please read the full text to understand what actions will and will not be tolerated.
Package Manager
This project uses Yarn 4 as its package manager. The correct version is automatically installed via Corepack when you run yarn install.
To get started:
- Make sure you have Node.js installed (see
.nvmrcfor the required version) - Enable Corepack:
corepack enable - Install dependencies:
yarn install
1. Our Design Principles
Note that we value performance, simplicity of implementation, and detailed documentations. We do not aim for supporting a variety of features and options. Our goal is to provide a small set of performant and well-functioning utilities.
1.1 Development Scope
es-toolkit
es-toolkit is a high-quality library of utility functions commonly used in modern JavaScript projects.
We focus on implementing functions that are difficult to create with JavaScript's built-in methods but are frequently needed and useful.
Examples include delay, windowed, keyBy, mapValues, camelCase, and toSnakeCaseKeys.
We don't implement functions that can be easily replaced with modern JavaScript, such as:
isArray(useArray.isArrayinstead)isNaN(useNumber.isNaNinstead)isNumber(usetypeof value === 'number'instead)min(useMath.min()instead)
For functions covered by TC39 proposals, we won't implement them once they reach Stage 3. We may consider adding functions from earlier proposals (Stage 2.7 or below) if there's a clear need, but we'll deprecate them once the proposal advances to Stage 3 or beyond—since at that point, using the native implementation is the better choice.
es-toolkit/compat
To help projects using Lodash migrate easily to es-toolkit, we implement all functions provided by Lodash.
1.2 Performance
All functions es-toolkit provides should be more performant than or similar with that of alternative libraries provide.
We measure the performance of our library every time our code is edited. We are using Vitest's benchmark feature. For our benchmark code, please refer to our benchmark directory.
When a new functionality is added, a benchmark code should be added. Please add screenshots of the benchmarks when opening a pull request for easy reference and history tracking.
1.3 Simplicity
We value implementation and interface simplicity over a variety of features for performance, code readability, and easy maintenance. Our functions will not provide complex options to suit every use case.
In this manner, instead of having complex options of making full use of overloading, etc, to support edge cases, we aim to provide the simplest interface and implementation for the most common 85% use cases.
We recognize that there are multiple approaches to achieving the same functionality. If the performance difference is less than 10%, please follow our coding style guidelines:
1. Prefer for loops over reduce.
In most cases, we prefer using for loops over reduce. This is because maintaining immutability with reduce can be challenging without tools like immer, and functional programming typically allows local mutability.
For instance, we prefer implementing keyBy using a for ... of loop instead of reduce.
export function keyBy<T, K extends PropertyKey>(arr: readonly T[], getKeyFromItem: (item: T) => K): Record<K, T> {
const result = {} as Record<K, T>;
for (const item of arr) {
const key = getKeyFromItem(item);
result[key] = item;
}
return result;
}
2. Prefer built-in JavaScript functions and operators.
We prefer using built-in JavaScript functions, methods, or operators like Array.isArray(), typeof value === 'string', and Number.isNaN(). Avoid using custom functions such as isArray(), isString(), or isNaN() from es-toolkit or other libraries.
This helps keep the code more concise, eliminates unnecessary function calls, and reduces coupling between functions.
1.4 Types
Accurate types are a core goal of es-toolkit, and so is consistency with TypeScript's own type behavior.
es-toolkit aims to return the same types as TypeScript's strict mode—the most widely used configuration. For example, result1 and result2 below should have the same type, since result2 is essentially just a wrapper around what result1 does directly:
import { sample } from 'es-toolkit';
const arr = [1, 2, 3];
const result1 = arr[Math.floor(Math.random() * arr.length)]; // inferred as `number` in TypeScript strict mode
const result2 = sample(arr); // should likewise be inferred as `number`
Options that default to false even within strict mode—such as noUncheckedIndexedAccess—are not considered when determining type compatibility in es-toolkit.
1.5 Documentation
All of our functions should be documented in detail for easy reference. All functions should have the JSDoc and corresponding documents in our documentation directory for all of their features.
Our primary language is English, but we strive to support documents in Korean, Japanese, and Simplified Chinese as well. If you have trouble writing documents in a foreign language, please let our contributors know, and we will help provide the necessary translations.
2. Coding Conventions
Here are the coding conventions we follow in the es-toolkit repository:
2.1 Use short names for type parameters
- Use
Tfor elements, like in difference. - Use
Efor errors, like in attempt. - Use
Kfor keys, like in groupBy.
3. Issues
You can contribute to es-toolkit via:
- Improving our docs
- Reporting a bug in our issues tab
- Requesting a new feature or package
- Having a look at our issue list to see what's to be fixed
4. Pull Requests
You can raise your own pull request. The title of your pull request should match the following format:
<type>[function names]: <description>
We do not care about the number, or style of commits in your history, because we squash merge every PR into main.
Feel free to commit in whatever style you feel comfortable with.
4.1 Type
Type must be one of those
if you changed shipped code :
- feat - for any new functionality additions
- fix - for any fixes that don't add new functionality
if you haven't changed shipped code :
- docs - if you only change documentation
- test - if you only change tests
other :
- chore - anything else
4.2 Function Names
The name of function that you made changes. (ex: debounce, throttle)
If you made changes across multiple packages, writing package scope is optional.
4.3 Description
A clear and concise description of what the pr is about.
5. Writing Documentation
Every function ships docs in four languages. Keep them in sync:
docs/reference/{category}/{fn}.md(English)docs/ko/reference/{category}/{fn}.md(Korean, in 해요체)docs/ja/reference/{category}/{fn}.md(Japanese)docs/zh_hans/reference/{category}/{fn}.md(Simplified Chinese)
For canonical examples, see sum and toCamelCaseKeys.
5.1 Template
# {function name}
{one-line description}
```typescript
{short example code}
```
## Usage
### `{signature}`
{Short paragraph: when to use it, then how it behaves. Add inline examples between paragraphs as needed.}
```typescript
import { {function name} } from 'es-toolkit/{category}';
// Short comment describing what this example shows.
{example call}
// Returns: {result}
```
#### Parameters
- `{name}` (`{type}`): {description}.
- `{name}` (`{type}`, optional): {description}. Defaults to `{default}`.
#### Returns
(`{type}`): {description}.
5.2 Filling it in
- Title: the function name with no suffix (
# sum,# toCamelCaseKeys). - One-line description: summarize the behavior in one sentence. If a non-obvious term appears (e.g. "camelCase"), add one short follow-up paragraph explaining it.
- Short example code: use descriptive variable names (
arr,numbers,obj) over concrete values so the interface is obvious at a glance. ### \signature``: one heading per overload. Merge overloads when possible; split only when the behavior is genuinely different (e.g. arrays vs. objects).- Body prose: lead with "when to use it", then describe behavior in flowing sentences — never the "Description: …" colon style. Open each example block with
import { ... } from 'es-toolkit/{category}'and put a one-line comment above each call. - Parameters:
- `name` (`type`): description.. For optionals, appendoptionalto the type and include the default. - Returns: type in parentheses first, then the description.
5.3 Style
- Use plain words (e.g. "arrays of the same length" instead of "uniform arrays").
- Prefer everyday JavaScript terms (e.g. "array or object" instead of "collection").
- In non-English versions, unfold English jargon into a natural local-language phrase (e.g. "값이 참으로 평가되는" instead of "truthy").