LinQ for TypeScript
linqts is a TypeScript library that ports LINQ (Language Integrated Query) capabilities, familiar to C# developers, to JavaScript and TypeScript environments. It provides a `List<T>` class that offers a rich set of methods for querying and manipulating collections in a fluent, declarative style, including operations like `Where`, `Select`, `Join`, `GroupBy`, `Min`, and `Max`. The library is currently stable at version 3.2.0 and maintains an active development cadence with major releases approximately annually and more frequent minor and patch updates addressing features and bug fixes. Its primary differentiator is the direct porting of the LINQ API surface, which makes it intuitive for developers coming from a .NET background, providing strong type safety through TypeScript.
Common errors
-
TypeError: list.Min is not a function or TypeError: Argument of type '(x: SomeType) => string' is not assignable to parameter of type '((arg: T) => number) | undefined'
cause Attempting to use `Min()` or `Max()` without providing a selector function or incorrect generic types after v3.0.0 made these methods generic.fixProvide a selector function to `Min()` or `Max()` to specify the property to compare, e.g., `list.Min(item => item.value)`. -
TypeError: Cannot read properties of undefined (reading 'Where') or TypeError: List is not a constructor
cause Incorrect import statement for the `List` class, often attempting to use a default import instead of a named import, or incorrect CommonJS require.fixEnsure you use `import { List } from 'linqts';` for ESM/TypeScript or `const { List } = require('linqts');` for CommonJS. -
Property 'ToDictionary' does not exist on type 'List<MyType>' or runtime error with unexpected `ToDictionary` behavior.
cause Usage of `ToDictionary()` with an incorrect signature or misunderstanding its updated behavior after v2.0.0, especially regarding strict mode implications or key uniqueness.fixConsult the `linqts` documentation for `ToDictionary()` in version 2.0.0 and above. Ensure your key selector returns unique keys or handle potential collisions as per the new behavior.
Warnings
- breaking The `Min()` and `Max()` functions are now generic. Code relying on the non-generic versions or specific type inference may require updates.
- breaking The behavior of `ToDictionary()` and all `*OrDefault()` functions (e.g., `FirstOrDefault()`, `SingleOrDefault()`) changed significantly, primarily due to stricter TypeScript support. Additionally, strict mode support was introduced.
- gotcha `ElementAtOrDefault()` was fixed to return `undefined` when the index is out of range, instead of throwing an error. This is a behavioral change.
- gotcha Older versions (prior to v1.14.4) had issues with module resolution for TypeScript projects when building for CommonJS, potentially causing errors.
Install
-
npm install linqts -
yarn add linqts -
pnpm add linqts
Imports
- List
const List = require('linqts').List;import { List } from 'linqts'; - ListConstructor
import List from 'linqts'; new List<MyType>(myArray);
import { List } from 'linqts'; new List<MyType>(myArray); - Iterable/Spread
import { List } from 'linqts'; const myList = new List([1,2,3]); for (const item of myList) {}import { List } from 'linqts'; const myList = new List([1,2,3]); [...myList]
Quickstart
import { List } from 'linqts';
interface Person { Name: string; Age: number; }
interface Pet { Name: string; Owner: Person; Type: string; }
const people: Person[] = [
{ Name: 'Alice', Age: 30 },
{ Name: 'Bob', Age: 25 },
{ Name: 'Charlie', Age: 35 }
];
const pets: Pet[] = [
{ Name: 'Fido', Owner: people[0], Type: 'Dog' },
{ Name: 'Whiskers', Owner: people[1], Type: 'Cat' },
{ Name: 'Buddy', Owner: people[0], Type: 'Dog' }
];
// Example 1: Filtering and mapping
const youngAdultsNames = new List(people)
.Where(p => p.Age < 30)
.Select(p => p.Name)
.ToArray();
console.log('Young Adults Names:', youngAdultsNames); // Expected: ['Bob']
// Example 2: Joining collections
const petsByOwner = new List(people).Join(
pets,
person => person,
pet => pet.Owner,
(person, pet) => ({ OwnerName: person.Name, PetName: pet.Name, PetType: pet.Type })
);
console.log('Pets by Owner:', petsByOwner.ToArray());
/* Expected: [
{ OwnerName: 'Alice', PetName: 'Fido', PetType: 'Dog' },
{ OwnerName: 'Bob', PetName: 'Whiskers', PetType: 'Cat' },
{ OwnerName: 'Alice', PetName: 'Buddy', PetType: 'Dog' }
]*/