toss / es-toolkit

A modern JavaScript utility library that's 2-3 times faster and up to 97% smaller—a major upgrade to lodash.
https://es-toolkit.slash.page
Other
6.23k stars 261 forks source link

Chainable API #415

Open mfulton26 opened 3 weeks ago

mfulton26 commented 3 weeks ago

I just discovered this library and it looks great. What do you think of supporting a chainable API too?

Pure functions are nice but when a developer needs to use multiple methods in a row it gets annoying to have to define intermediary variables or to nest function calls. JavaScript doesn't have a pipeline operator but prototypes can be safely augmented these days using symbols (rather than strings which can cause conflicts because they are not unique).

Example

import $ from 'es-toolkit/$';
import 'es-toolkit/$/array/chunk';

// Splits an array of numbers into sub-arrays of length 2
[1, 2, 3, 4, 5][$.chunk](2);
// Returns: [[1, 2], [3, 4], [5]]

// Splits an array of strings into sub-arrays of length 3
['a', 'b', 'c', 'd', 'e', 'f', 'g'][$.chunk](3);
// Returns: [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]

Implementation

Augmenting modules should be able to be programmatically generated from pure functions (e.g. using ts-morph):

// es-toolkit/$.ts
export interface Symbols {};
export default {} as Symbols;
// es-toolkit/$/.symbols/chunk.ts
import $ from 'es-toolkit/$.ts';

const key = 'chunk';
const value = Symbol(`es-toolkit/${key}`);

declare module 'es-toolkit/$.ts' {
  interface Symbols {
    [key]: typeof value;
  }
}

Object.defineProperty($, key, { value });
// es-toolkit/$/array/chunk.ts
import 'es-toolkit/.symbols/chunk';
import { chunk } from 'es-toolkit/array/chunk';

const key = $.chunk;
function value<T>(this: T[], size: number): T[] {
  return chunk(this, size);
}

declare global {
  interface Array<T> {
    [key](size: number): T[];
  }
}

Object.defineProperty(Array.prototype, key, { value });
D-Sketon commented 3 weeks ago

Do modifications to the Array.prototype make the sideEffects become true?

mfulton26 commented 3 weeks ago

Do modifications to the Array.prototype make the sideEffects become true?

I'm not familiar with that flag. Is that a webpack specific flag? I think it would, but the side-effects modules could be published under a different package name while reusing code to avoid such.

mfulton26 commented 3 weeks ago

After looking at some docs it looks like this can be set to true for only some modules. e.g.

  "sideEffects": ["./src/$/**/*.ts"]