A port of System.Linq.Enumerable from the .NET framework to TypeScript, using a unique and safe design pattern which directly exposes the Enumerable class as a collection of polymorphic extension methods to all of the classes defined in the core language specification that implement the iterable protocol.
enumerable-ts is designed to fulfill the same purpose as the Enumerable class from C#. It provides a collection of extension methods to the built-in classes and uses deferred execution for declaring complex queries and iterating large collections with efficient memory consumption.
This is possible through the use of generator functions. Generator functions provide a way of expressing deferred execution consumed through the iterator protocol. This allows complex queries to be constructed and iterated without buffering intermediate copies of the entire underlying collection in memory.
$ npm i --save enumerable-ts
import 'enumerable-ts'
require('enumerable-ts')
const array: (number | null)[] = [1, 2, 3, 4, null, 6, 7, 8, 9]
const sum = array
.where(Boolean)
.select(i => i * 2)
.aggregate((sum, val) => sum + val, 0)
console.log(sum) // 80
Because of deferred execution, the original array
is only iterated once by aggregate()
, which calls and consumes this[Symbol.iterator]
to yield the sequence of non-null, doubled integers being summed.
array.concat(…)
->enumerable.concat(…)
*array.every(…)
->enumerable.all(…)
array.filter(…)
->enumerable.where(…)
array.find(…)
->enumerable.first(…)
array.flatMap(…)
->enumerable.selectMany(…)
array.map(…)
->enumerable.select(…)
array.reduce(…)
->enumerable.aggregate(…)
array.reduceRight(…)
->enumerable.aggregateRight(…)
array.reverse()
->enumerable.reverse(…)
*array.slice(begin)
->enumerable.skip(begin)
array.slice(begin, end)
->enumerable.skip(begin).take(end - begin)
array.some(…)
->enumerable.any(…)
array.sort(…)
->enumerable.orderBy(…)
* To call these methods on an array, use array.toEnumerable().method(…)
or Enumerable.prototype.method.call(array, …)
On the left-hand side, the operation occurs immediately and returns the result. If the result is an array, the operation on the right-hand side is deferred and an Enumerable
is returned, which will apply the operation when it is iterated implicitly using for...of
or explicitly using enumerable[Symbol.iterator]()
. If the result is a boolean, element, or accumulator, then the operation on the right-hand side still occurs immediately, but the method is available on Enumerable.prototype
, while the left-hand side is not.
There are many more methods available on IEnumerable
.
Yes, the module is available on npm pre-transpiled to ECMAScript 2015. There is no plan to make this backwards-compatible, as the only way to modify a built-in prototype chain (__proto__
) is platform-specific and not standardized within the ECMAScript 5 specification.
Array
, TypedArray
, String
, Map
, and Set
.
Why are concat()
, join()
, reverse()
, and toJSON()
only available on Enumerable
and not on the IEnumerable
interface?
In order to remain polymorphic, all the IEnumerable
interface methods must be forward-compatible with the methods on each of its implementing classes. Since many of the built-in Iterables in JavaScript already implement these methods with conflicting signatures, it's by design that these methods are only available on instances of the concrete Enumerable
class.
However, by using explicit calls to these methods on the Enumerable
class like Enumerable.prototype.concat.join(array, …)
, they can still be directly applied to instances of the built-in classes without violating the principles of polymorphism.
- Documentation of usage with example code
- Full port of core
System.Linq.Enumerable
methods - Full port of MoreLINQ methods
- Node.js support
- Browser support
- Require.js support
- Universal Module Definition
- Separate exports with and without global-modifying side-effects (similar to
colors
)
Do you have feature requests, bug reports, or ideas for improving this project? Please open new issues on the github repository with details about your inquiry.
Copyright © 2018 Patrick Roberts
MIT License