Skip to content

Instantly share code, notes, and snippets.

@moander
Last active March 10, 2024 08:01
Show Gist options
  • Save moander/c61c0e01027d7252a17f9d507985ac31 to your computer and use it in GitHub Desktop.
Save moander/c61c0e01027d7252a17f9d507985ac31 to your computer and use it in GitHub Desktop.
Lodash on Array.prototype
// eslint-disable
// Access prefixed lodash array functions on the Array prototype.
// For example [3,2,1].js1SortBy(x => x)
// https://gist.github.com/moander/c61c0e01027d7252a17f9d507985ac31
import type { Dictionary, ListIteratee, LoDashImplicitWrapper, Many, PropertyName, ValueIteratee, ValueIterateeCustom, ValueIteratorTypeGuard, Object as _Object } from 'lodash'
import {
chunk as js1Chunk,
countBy as js1CountBy,
groupBy as js1GroupBy,
keyBy as js1KeyBy,
maxBy as js1MaxBy,
meanBy as js1MeanBy,
minBy as js1MinBy,
orderBy as js1OrderBy,
partition as js1Partition,
remove as js1Remove,
sampleSize as js1SampleSize,
shuffle as js1Shuffle,
sortBy as js1SortBy,
sumBy as js1SumBy,
takeRightWhile as js1TakeRightWhile,
takeWhile as js1TakeWhile,
uniq as js1Uniq,
uniqBy as js1UniqBy,
} from 'lodash'
extendWithLodashArray(Array.prototype, 'js1Chunk', js1Chunk)
extendWithLodashArray(Array.prototype, 'js1CountBy', js1CountBy)
extendWithLodashArray(Array.prototype, 'js1GroupBy', js1GroupBy)
extendWithLodashArray(Array.prototype, 'js1KeyBy', js1KeyBy)
extendWithLodashArray(Array.prototype, 'js1MaxBy', js1MaxBy)
extendWithLodashArray(Array.prototype, 'js1MeanBy', js1MeanBy)
extendWithLodashArray(Array.prototype, 'js1MinBy', js1MinBy)
extendWithLodashArray(Array.prototype, 'js1OrderBy', js1OrderBy)
extendWithLodashArray(Array.prototype, 'js1Partition', js1Partition)
extendWithLodashArray(Array.prototype, 'js1Remove', js1Remove)
extendWithLodashArray(Array.prototype, 'js1SampleSize', js1SampleSize)
extendWithLodashArray(Array.prototype, 'js1Shuffle', js1Shuffle)
extendWithLodashArray(Array.prototype, 'js1SortBy', js1SortBy)
extendWithLodashArray(Array.prototype, 'js1SumBy', js1SumBy)
extendWithLodashArray(Array.prototype, 'js1TakeRightWhile', js1TakeRightWhile)
extendWithLodashArray(Array.prototype, 'js1TakeWhile', js1TakeWhile)
extendWithLodashArray(Array.prototype, 'js1Uniq', js1Uniq)
extendWithLodashArray(Array.prototype, 'js1UniqBy', js1UniqBy)
// Tell typescript about our Prototype extensions.
// Docs and function specs come from @types/lodash.
declare global {
interface Array<T> {
/**
* Creates an array of elements split into groups the length of size. If collection can’t be split evenly, the
* final chunk will be the remaining elements.
*
* @param size The length of each chunk.
* @return Returns the new array containing chunks.
*/
js1Chunk(size?: number): Array<T[]>
/**
* Creates an object composed of keys generated from the results of running each element of collection through
* iteratee. The corresponding value of each key is the number of times the key was returned by iteratee. The
* iteratee is invoked with one argument: (value).
*
* @param iteratee The function invoked per iteration.
* @return Returns the composed aggregate object.
*/
js1CountBy(iteratee?: ValueIteratee<T>): _Object<Dictionary<number>>
/**
* Creates an object composed of keys generated from the results of running each element of collection through
* iteratee. The corresponding value of each key is an array of the elements responsible for generating the
* key. The iteratee is invoked with one argument: (value).
*
* @param iteratee The function invoked per iteration.
* @return Returns the composed aggregate object.
*/
js1GroupBy(iteratee?: ValueIteratee<T>): Record<any, T[]>
/**
* Creates an object composed of keys generated from the results of running each element of collection through
* iteratee. The corresponding value of each key is the last element responsible for generating the key. The
* iteratee function is invoked with one argument: (value).
*
* @param iteratee The function invoked per iteration.
* @return Returns the composed aggregate object.
*/
js1KeyBy(iteratee?: ValueIterateeCustom<T, PropertyName>): _Object<Dictionary<T>>
/**
* This method is like `_.max` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the criterion by which
* the value is ranked. The iteratee is invoked with one argument: (value).
*
* @category Math
* @param iteratee The iteratee invoked per element.
* @returns Returns the maximum value.
* @example
*
* var objects = [{ 'n': 1 }, { 'n': 2 }];
*
* _.maxBy(objects, function(o) { return o.n; });
* // => { 'n': 2 }
*
* // using the `_.property` iteratee shorthand
* _.maxBy(objects, 'n');
* // => { 'n': 2 }
*/
js1MaxBy(iteratee?: ValueIteratee<T>): T | undefined
/**
* Computes the mean of the provided properties of the objects in the `array`
*
* @category Math
* @param iteratee The iteratee invoked per element.
* @returns Returns the mean.
* @example
*
* _.mean([{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }], 'n');
* // => 5
*/
js1MeanBy(iteratee?: ValueIteratee<T>): number
/**
* This method is like `_.min` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the criterion by which
* the value is ranked. The iteratee is invoked with one argument: (value).
*
* @category Math
* @param iteratee The iteratee invoked per element.
* @returns Returns the minimum value.
* @example
*
* var objects = [{ 'n': 1 }, { 'n': 2 }];
*
* _.minBy(objects, function(o) { return o.a; });
* // => { 'n': 1 }
*
* // using the `_.property` iteratee shorthand
* _.minBy(objects, 'n');
* // => { 'n': 1 }
*/
js1MinBy(iteratee?: ValueIteratee<T>): T | undefined
/**
* This method is like `_.sortBy` except that it allows specifying the sort
* orders of the iteratees to sort by. If `orders` is unspecified, all values
* are sorted in ascending order. Otherwise, specify an order of "desc" for
* descending or "asc" for ascending sort order of corresponding values.
*
* @category Collection
* @param [iteratees=[_.identity]] The iteratees to sort by.
* @param [orders] The sort orders of `iteratees`.
* @param [guard] Enables use as an iteratee for functions like `_.reduce`.
* @returns Returns the new sorted array.
* @example
*
* var users = [
* { 'user': 'fred', 'age': 48 },
* { 'user': 'barney', 'age': 34 },
* { 'user': 'fred', 'age': 42 },
* { 'user': 'barney', 'age': 36 }
* ];
*
* // sort by `user` in ascending order and by `age` in descending order
* _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]]
*/
js1OrderBy(iteratees?: Many<keyof T>, orders?: Many<boolean | 'asc' | 'desc'>): Array<T>
/**
* Creates an array of elements split into two groups, the first of which contains elements predicate returns truthy for,
* while the second of which contains elements predicate returns falsey for.
* The predicate is invoked with three arguments: (value, index|key, collection).
*
* @param callback The function called per iteration.
* @return Returns the array of grouped elements.
*/
js1Partition<U extends T>(callback: ValueIteratorTypeGuard<T, U>): LoDashImplicitWrapper<[U[], Array<Exclude<T, U>>]>
js1Partition(callback: ValueIteratee<T>): LoDashImplicitWrapper<[T[], T[]]>
/**
* Removes all elements from array that predicate returns truthy for and returns an array of the removed
* elements. The predicate is invoked with three arguments: (value, index, array).
*
* Note: Unlike _.filter, this method mutates array.
*
* @param predicate The function invoked per iteration.
* @return Returns the new array of removed elements.
*/
js1Remove(predicate?: ListIteratee<T>): Array<T>
/**
* Gets n random elements at unique keys from collection up to the size of collection.
*
* @param n The number of elements to sample.
* @return Returns the random elements.
*/
js1SampleSize(n?: number): Array<T>
/**
* Creates an array of shuffled values, using a version of the Fisher-Yates shuffle.
*
* @return Returns the new shuffled array.
*/
js1Shuffle(): Array<T>
/**
* Creates an array of elements, sorted in ascending order by the results of
* running each element in a collection through each iteratee. This method
* performs a stable sort, that is, it preserves the original sort order of
* equal elements. The iteratees are invoked with one argument: (value).
*
* @category Collection
* @param [iteratees=[_.identity]]
* The iteratees to sort by, specified individually or in arrays.
* @returns Returns the new sorted array.
* @example
*
* var users = [
* { 'user': 'fred', 'age': 48 },
* { 'user': 'barney', 'age': 36 },
* { 'user': 'fred', 'age': 42 },
* { 'user': 'barney', 'age': 34 }
* ];
*
* _.sortBy(users, function(o) { return o.user; });
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]]
*
* _.sortBy(users, ['user', 'age']);
* // => objects for [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]]
*
* _.sortBy(users, 'user', function(o) {
* return Math.floor(o.age / 10);
* });
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]]
*/
js1SortBy(...iteratees: Array<Many<ListIteratee<T>>>): Array<T>
/**
* This method is like `_.sum` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the value to be summed.
* The iteratee is invoked with one argument: (value).
*
* @category Math
* @param [iteratee=_.identity] The iteratee invoked per element.
* @returns Returns the sum.
* @example
*
* var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
*
* _.sumBy(objects, function(o) { return o.n; });
* // => 20
*
* // using the `_.property` iteratee shorthand
* _.sumBy(objects, 'n');
* // => 20
*/
js1SumBy(iteratee?: ((value: T) => number) | string): number
/**
* Creates a slice of array with elements taken from the end. Elements are taken until predicate returns
* falsey. The predicate is invoked with three arguments: (value, index, array).
*
* @param predicate The function invoked per iteration.
* @return Returns the slice of array.
*/
js1TakeRightWhile(predicate?: ListIteratee<T>): Array<T>
/**
* Creates a slice of array with elements taken from the beginning. Elements are taken until predicate returns
* falsey. The predicate is invoked with three arguments: (value, index, array).
*
* @param predicate The function invoked per iteration.
* @return Returns the slice of array.
*/
js1TakeWhile(predicate?: ListIteratee<T>): Array<T>
/**
* Creates a duplicate-free version of an array, using
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
* for equality comparisons, in which only the first occurrence of each element
* is kept.
*
* @category Array
* @returns Returns the new duplicate free array.
* @example
*
* _.uniq([2, 1, 2]);
* // => [2, 1]
*/
js1Uniq(): Array<T>
/**
* This method is like `_.uniq` except that it accepts `iteratee` which is
* invoked for each element in `array` to generate the criterion by which
* uniqueness is computed. The iteratee is invoked with one argument: (value).
*
* @category Array
* @param [iteratee=_.identity] The iteratee invoked per element.
* @returns Returns the new duplicate free array.
* @example
*
* _.uniqBy([2.1, 1.2, 2.3], Math.floor);
* // => [2.1, 1.2]
*
* // using the `_.property` iteratee shorthand
* _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
* // => [{ 'x': 1 }, { 'x': 2 }]
*/
js1UniqBy(iteratee: ValueIteratee<T>): Array<T>
}
}
function extendWithLodashArray(proto: any, protoKey: string, fn: any) {
if (!proto[protoKey]) {
Object.defineProperty(proto, protoKey, {
value: function (this: any, ...args: any[]) {
return fn(this, ...args)
},
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment