LinqToTypeScript
LINQ to TypeScript
- **Implementation of [LINQ](https://en.wikipedia.org/wiki/Language_Integrated_Query) for TypeScript** - **Targets TypeScript 5.6.X and ES 2022** The project is written primarily in TypeScript, distributed under the MIT License license, first published in 2016. Key topics include: async, async-await, async-iteration, enumerable, es2019.
LINQ To TypeScript
- Implementation of LINQ for TypeScript
- Targets TypeScript 5.6.X and ES 2022
TypeScriptawait from([bing, google, quackQuackGo]) .asParallel() .selectAsync(downloadHtml) .select(getTitle) .toArray()
Getting Started
shnpm i linq-to-typescript
tsconfig.json
JSON"compilerOptions": { "target": "es2022", "lib": [ "es2022" ] }
- The
strictTS option is recommended.
Node.js
Node.js 17 or higher is required.
Note: This package is ESM-only. If your project uses CommonJS (
require), you'll need a bundler or interop shim.
Using the Library
With Wrappers
TypeScript// 0. Import Module import { from } from "linq-to-typescript" // To Use With Wrappers const evenNumbers = from([1, 2, 3, 4, 5, 6, 7, 8, 9]).where((x) => x % 2 === 0).toArray()
Without Wrappers
TypeScript// 0. Import Module import { initializeLinq, IEnumerable } from "linq-to-typescript" // 1. Declare that the JS types implement the IEnumerable interface declare global { interface Array<T> extends IEnumerable<T> { } interface Uint8Array extends IEnumerable<number> { } interface Uint8ClampedArray extends IEnumerable<number> { } interface Uint16Array extends IEnumerable<number> { } interface Uint32Array extends IEnumerable<number> { } interface Int8Array extends IEnumerable<number> { } interface Int16Array extends IEnumerable<number> { } interface Int32Array extends IEnumerable<number> { } interface Float32Array extends IEnumerable<number> { } interface Float64Array extends IEnumerable<number> { } interface Map<K, V> extends IEnumerable<[K, V]> { } interface Set<T> extends IEnumerable<T> { } interface String extends IEnumerable<string> { } } // 2. Bind Linq Functions to Array, Map, etc initializeLinq() // 3. Use without a wrapper type const evenNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9].where((x) => x % 2 === 0).toArray()
Examples
The examples folder contains runnable demos:
- primenumbers.ts — find primes using
range().where().all() - digitsofpi.ts — approximate π via the Nilakantha series with
range().select().aggregate() - paralleldownload.ts — download URLs in parallel with
asParallel().selectAsync()
ES6 Modules (ESM)
To use library with ES6 modules make sure that you specify "type": "module" in package.json
API
TypeDoc API Surface Documentation
LinqToTypeScript implements the functionality of the IEnumerable interface
- IEnumerable, IAsyncEnumerable, and IParallelEnumerable interfaces are based on,
- IEnumerable<T> Interface
- Some changes made due to conflicts with existing method names
- Some changes made due to limitations of JavaScript
IEnumerable
- Inspired by LINQ API Surface
- Has Async methods that return
PromiseorIAsyncEnumerable - Implements
Iterable<T> - Use
fromto wrap your arrays
IAsyncEnumerable
- Inspired by LINQ API Surface
- Has Async methods that return
PromiseorIAsyncEnumerable - For asynchronous iteration
- Implements
AsyncIterable<T>interface - Use
fromAsyncto wrap your AsyncIterable type
IParallelEnumerable
- Inspired by LINQ API Surface
- Has Async methods that return
PromiseorIParallelEnumerable - For asynchronous iteration in parallel (where possible)
- Implements
AsyncIterable<T>interface - Use
fromParallelto create a parallel enumeration
Shared Instance Methods
| Method | Async* | Tests Coverage | Notes |
|---|---|---|---|
| aggregate | No | Sync | |
| all | Yes | Sync, Async | |
| any | Yes | Sync, Async | |
| append | No | Sync | |
| average | Yes | Sync, Async | |
| chunk | No | Sync | |
| concatenate | No | Sync | Equivalent to .Concat but renamed to avoid conflict with JS |
| contains | Yes | Sync, Async | |
| count | Yes | Sync, Async | |
| defaultIfEmpty | No | Sync | |
| distinct | Yes | Sync, Async | |
| elementAt | No | Sync | |
| elementAtOrDefault | No | Sync | |
| except | Yes | Sync, Async | |
| first | Yes | Sync, Async | |
| firstOrDefault | Yes | Sync, Async | |
| each | Yes | Sync, Async | From List<T>.ForEach |
| groupBy | Yes | Sync, Async | |
| groupByWithSel | No | Sync | |
| groupJoin | Yes | Sync, Async | |
| intersect | Yes | Sync, Async | |
| joinByKey | No | Sync | |
| last | Yes | Sync, Async | |
| lastOrDefault | Yes | Sync, Async | |
| max | Yes | Sync, Async | |
| maxBy | Yes | Sync, Async | |
| min | Yes | Sync, Async | |
| minBy | Yes | Sync, Async | |
| ofType | No | Sync | |
| order | No | Sync | |
| orderBy | Yes | Sync, Async | |
| orderByDescending | Yes | Sync, Async | |
| orderDescending | No | Sync | |
| partition | Yes | Sync, Async | |
| prepend | No | Sync | |
| reverse | No | Sync | |
| select | Yes | Sync, Async | |
| selectMany | Yes | Sync, Async | |
| sequenceEquals | Yes | Sync, Async | |
| single | Yes | Sync, Async | |
| singleOrDefault | Yes | Sync, Async | |
| skip | No | Sync | |
| skipWhile | Yes | Sync, Async | |
| sum | Yes | Sync, Async | |
| take | No | Sync | |
| takeWhile | Yes | Sync, Async | |
| toArray | No | Sync | |
| toMap | Yes | Sync, Async | Equivalent to ToDictionary |
| toObject | Yes | Sync, Async | |
| toSet | No | Sync | Equivalent to ToHashSet. No comparer overload for JS. |
| union | Yes | Sync | |
| where | Yes | Sync, Async | |
| zip | Yes | Sync, Async |
* Async methods take an async function
Static Methods
| Method | Description | Async | Parallel | Tests Coverage |
|---|---|---|---|---|
| empty | Returns an empty enumerable | emptyAsync | emptyParallel | Test |
| enumerateObject | Yields [key, value] pairs from a plain object | enumerateObjectAsync | N/A | Test |
| flatten | Flattens a nested iterable one level deep | flattenAsync | flattenParallel | Test |
| range | Generates a sequence of integers from start to start+count | rangeAsync | rangeParallel | Test |
| repeat | Repeats a value N times | repeatAsync | repeatParallel | Test |
Index Methods
| Method | Notes |
|---|---|
| bindArray | Binds IEnumerable methods to an ArrayLike Iterable type |
| bindLinq | Binds IEnumerable methods to an Iterable type |
| bindLinqAsync | Binds IAsyncEnumerable methods to an AsyncIterable type |
| isEnumerable | Determines if source implements IEnumerable |
| isAsyncEnumerable | Determines if source implements IAsyncEnumerable |
| isParallelEnumerable | Determines if source implements IParallelEnumerable |
| initializeLinq | Binds to IEnumerable to Array Types, Map, Set, & String |
Exception Types
| Exception | Notes |
|---|---|
| ArgumentOutOfRangeException | Thrown when a passed in argument is invalid |
| InvalidOperationException | Thrown when no elements or no predicate match |
Comparers
Built-in comparers can be passed to methods like distinct, contains, sequenceEquals, except, intersect, and union.
| Export | Purpose |
|---|---|
EqualityComparer | Loose equality (==) |
StrictEqualityComparer | Strict equality (===) |
NumberComparer | Numeric ordering (for use with orderBy) |
StringifyComparer | Equality via JSON.stringify |
Design
Binding new APIs to Array Types
JavaScript doesn't have extension methods like in C#, therefore we extend the class itself with new methods.
Call initializeLinq to bind library functions to default Array methods,
The following collections support IEnumerable,
ArrayMapSetStringInt8ArrayInt16ArrayInt32ArrayUint8ArrayUint8ClampedArrayUint16ArrayUint32ArrayFloat32ArrayFloat64Array
Using Wrappers
NOTE: Wrappers are safer as they won't interfere with other libraries.
TypeScript// To Create an IEnumerable<T> import { from } from "linq-to-typescript" from(iterableIteratorOrArray) // To Create an IAsyncEnumerable<T> import { fromAsync } from "linq-to-typescript" fromAsync(asyncIterableIteratorOrPromiseArray) // To Create an IParallelEnumerable<T> // You have to specify the parallel generator function type import { fromParallel, ParallelGeneratorType } from "linq-to-typescript" fromParallel(ParallelGeneratorType.PromiseToArray, asyncFuncThatReturnsAnArray)
Issues and Questions
Q1: How does this compare to other LINQ libraries?
Other libraries tend to use eager evaluation and work with arrays instead of iterables.
Q2: Can I use your code?
With attribution; the code is licensed under MIT.
Q3: Why should I use this instead of lodash or something similar?
The whole library is written in TypeScript first and avoids typechecking done by TypeScript Language Service.
Lazy evaluation. Not much happens until you iterate over the enumerable or conver it to an Array, Map, etc.
Q4: Is IE11 supported?
No.
Q5: Can I contribute?
Please do!
Contributors
Showing top 3 contributors by commit count.
