Skip to content

jieny/typescript-extended-linq

 
 

Repository files navigation

typescript-extended-linq

This is a library that is a direct translation of System.Linq from .NET and many additional functions from MoreLINQ.

Table of Contents

  1. Installation
  2. Why use this library?
  3. Basic Usage
  4. Documentation

Installation:

npm i typescript-extended-linq

You can optionally bind the Linq functions to native types (arrays, maps, sets, strings, etc). Binding to native types adds the functions to the type's prototype. Always be mindful when modifying a native type's prototype. While these functions will not affect native functionality, it cannot be guaranteed that it will not affect other frameworks if they also modify prototypes.

Add the following at the start of your program to bind to native types (the eslint disable is only needed if you use that eslint rule):

/* eslint-disable @typescript-eslint/no-empty-interface */
import { bindLinqToNativeTypes } from 'typescript-extended-linq';

declare global {
  interface Array<T> extends Omit<IEnumerable<T>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Int8Array extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Int16Array extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Int32Array extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Uint8ClampedArray extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Uint16Array extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Uint32Array extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Float32Array extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Float64Array extends Omit<IEnumerable<number>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Map<K, V> extends Omit<IEnumerable<[K, V]>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface Set<T> extends Omit<IEnumerable<T>, 'forEach' | 'toString' | 'toJSON' | symbol> {}
  interface String
    extends Omit<IEnumerable<string>, 'endsWith' | 'startsWith' | 'split' | 'toString' | 'toJSON' | symbol> {}
}

bindLinqToNativeTypes();

You will then be able to see Linq methods on native types without needing to use the from() wrapper:

[1, 2, 3]
  .where(x => x > 1)
  .take(1)
  .toArray();

Any function that already existed on the native type (toString(), forEach() for example) will not be overridden and will continue to use the native function. Note that the call to bindLinqToNativeTypes must be done prior to using the functions on native types. This, for example, will not work:

foo.ts

export const foo = [1, 2, 3].where(x => x > 1).toArray();

index.ts

import { bindLinqToNativeTypes } from 'typescript-extended-linq';
import { foo } from './foo';

bindLinqToNativeTypes();

console.log(foo);

This will not work because the import line is before the bind function is ran and when that file is imported, it tries to use the 'where' function.

This, however, will work fine:

foo.ts

export function foo(): number[] {
  return [1, 2, 3].where(x => x > 1).toArray();
}

index.ts

import { bindLinqToNativeTypes } from 'typescript-extended-linq';
import { foo } from './foo';

bindLinqToNativeTypes();

console.log(foo());

Because the 'where' is not used until the foo function is invoked which is after the bind function is called.

If you only want to bind to certain types, you can pass in an optional object to do so (be sure to update the global type declarations):

import { bindLinqToNativeTypes } from 'typescript-extended-linq';

bindLinqToNativeTypes({ types: [Array] }); // Now only array will have new functions. Sets, Strings, Maps, etc will not.

You can also pass in optional functions to not bind to native types (once again, be sure to update the global type declarations):

import { bindLinqToNativeTypes } from 'typescript-extended-linq';

bindLinqToNativeTypes({ types: [Array], functionsToIgnore: ['aggregate'] }); // Only arrays will have new functions but it will not have aggregate.

Why use this library?

Additional Functionality

  • Native JavaScript/TypeScript provides many useful functions that are similar to LINQ (such as map, filter, reduce, etc). This library fills in the missing gaps with many functions that are not included in the native language such as joins, multi-level ordering, grouping, etc.

Additional Collections

Deferred Execution

TypeScript First

  • This library was written in Typescript so type definitions are included out of the box and are always up to date. The Typescript source code is included in the package so users can easily look at the implementation.
  • Documentation is also auto-generated on every release so they will always be up to date as well.

Basic Usage:

import { from } from 'typescript-extended-linq';

const items = [
  { id: 1, foo: 'a', bar: new Date('8/1/2021') },
  { id: 2, foo: 'a', bar: new Date('8/1/2021') },
  { id: 2, foo: 'b', bar: new Date('8/1/2021') },
  { id: 2, foo: 'a', bar: new Date('9/1/2021') },
  { id: 3, foo: 'a', bar: new Date('8/1/2021') },
  { id: 3, foo: 'b', bar: new Date('8/1/2021') }
];

const query = from(items)
  .where(item => item.id % 2 === 0)
  .orderBy(item => item.id)
  .thenBy(item => item.foo)
  .thenBy(item => item.bar);

/**
 * Will log:
 * [
 *  { id: 2, foo: 'a', bar: 2021-08-01T07:00:00.000Z },
 *  { id: 2, foo: 'a', bar: 2021-09-01T07:00:00.000Z },
 *  { id: 2, foo: 'b', bar: 2021-08-01T07:00:00.000Z }
 * ]
 */
console.log(query.toArray());

const sumOfIds = query.sum(item => item.id);

// Will log 6
console.log(sumOfIds);

const distinct = query.distinctBy(item => item.id).toArray();

// Will log [ { id: 2, foo: 'a', bar: 2021-08-01T07:00:00.000Z } ]
console.log(distinct);

Each function also can be used directly by passing in the source iterable as the first argument:

import { join } from 'typescript-extended-linq';

type Person = { name: string };
type Pet = { name: string; owner: Person };

const magnus: Person = { name: 'Magnus' };
const terry: Person = { name: 'Terry' };
const adam: Person = { name: 'Adam' };
const john: Person = { name: 'John' };

const barley: Pet = { name: 'Barley', owner: terry };
const boots: Pet = { name: 'Boots', owner: terry };
const whiskers: Pet = { name: 'Whiskers', owner: adam };
const daisy: Pet = { name: 'Daisy', owner: magnus };
const scratchy: Pet = { name: 'Scratchy', owner: { name: 'Bob' } };

const people = from([magnus, terry, adam, john]);
const pets = from([barley, boots, whiskers, daisy, scratchy]);

const result = join(
  people,
  pets,
  person => person,
  pet => pet.owner,
  (person, pet) => ({ ownerName: person.name, pet: pet.name })
).toArray();

/**
 * Will log:
 * [
 *   { ownerName: 'Magnus', pet: 'Daisy' },
 *   { ownerName: 'Terry', pet: 'Barley' },
 *   { ownerName: 'Terry', pet: 'Boots' },
 *   { ownerName: 'Adam', pet: 'Whiskers' }
 * ]
 */
console.log(result);

Documentation

Please see full documentation here.

Applies an accumulator function over a sequence.

Determines whether all elements of a sequence satisfy a condition.

Determines whether any element of a sequence exists or satisfies a condition.

Appends a value to the end of the sequence.

Returns the input as an IEnumerable.

Determines whether or not the number of elements in the sequence is greater than or equal to the given integer.

Determines whether or not the number of elements in the sequence is lesser than or equal to the given integer.

Computes the average of a sequence of numeric values.

Split the elements of a sequence into chunks of size at most chunkSize.

Concatenates two sequences.

Determines whether a sequence contains a specified element.

Returns the number of elements in a sequence.

Returns the elements of the specified sequence or the specified value in a singleton collection if the sequence is empty.

Returns distinct elements from a sequence.

Returns distinct elements from a sequence according to a specified key selector function.

Returns the element at a specified index in a sequence. A negative index can be used to get element starting from the end.

Returns the element at a specified index in a sequence or null if the index is out of range. A negative index can be used to get element starting from the end.

Determines whether the end of the first sequence is equivalent to the second sequence.

Produces the set difference of two sequences.

Produces the set difference of two sequences according to a specified key selector function.

Returns the first element in a sequence. Throws if sequence contains no elements.

Returns the first element in a sequence. Returns null if sequence contains no elements

Returns a new IEnumerable with all sub-iterable elements concatenated into it recursively up to the specified depth.

Iterates the sequence and calls an action on each element.

Performs a full outer join on two heterogeneous sequences.

Performs a full outer join on two homogeneous sequences.

Groups the elements of a sequence according to a specified key selector function.

Correlates the elements of two sequences based on key equality, and groups the results.

Produces the set intersection of two sequences.

Produces the set intersection of two sequences according to a specified key selector function.

Performs an inner join by correlating the elements of two sequences based on matching keys.

Returns the last element of a sequence.

Returns the last element of a sequence, or null if the sequence contains no elements.

Performs a left outer join on two heterogeneous sequences. Additional arguments specify key selection functions and result projection functions.

Performs a left outer join on two homogeneous sequences. Additional arguments specify key selection functions and result projection functions.

Returns the maximum value in a sequence of values.

Returns the maximum value in a generic sequence according to a specified key selector function.

Returns the min value in a sequence of values.

Returns the min value in a generic sequence according to a specified key selector function.

Filters the elements of an IEnumerable based on a specified type.

Sorts the elements of a sequence in ascending order.

Sorts the elements of a sequence in descending order.

Executes the given action on each element in the source sequence and yields it.

Adds a value to the beginning of the sequence.

Computes the quantile of a sequence.

Inverts the order of the elements in a sequence.

Performs a right outer join on two heterogeneous sequences.

Performs a right outer join on two homogeneous sequences.

Projects each element of a sequence into a new form.

Projects each element of a sequence to an IEnumerable and flattens the resulting sequences into one sequence.

Determines whether two sequences are equal by comparing the elements.

Returns a new IEnumerable of the input sequence in random order.

Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.

Returns a single, specific element of a sequence, or null if that element is not found.

Bypasses a specified number of elements in a sequence and then returns the remaining elements.

Returns a new enumerable collection that contains the elements from source with the last count elements of the source collection omitted.

Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.

Splits the source sequence by a separator.

Determines whether the beginning of the first sequence is equivalent to the second sequence.

Computes the sum of a sequence of numeric values.

Returns a specified number of contiguous elements from the start of a sequence.

Returns every N-th element of a sequence.

Returns a new enumerable collection that contains the last count elements from source.

Returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements.

Performs a subsequent ordering of the elements in a sequence in ascending order.

Performs a subsequent ordering of the elements in a sequence in descending order.

Creates a new instance of the passed in ctor with the Iterable as input.

Converts the source sequence into an array.

Creates a Map<TKey, TValue> from an IEnumerable according to specified key selector.

Returns an object with keys selected by keySelector and values of TSource.

Creates a Set from an IEnumerable.

Produces the set union of two sequences.

Produces the set union of two sequences according to a specified key selector function.

Filters a sequence of values based on a predicate.

Produces the symmetric difference of two sequences.

Produces the symmetric difference of two sequences according to a specified key selector function.

Produces a sequence of tuples with elements from the two specified sequences.

About

C# linq style API for TypeScript

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 99.9%
  • Other 0.1%