TypeScript library provides strongly-typed, queryable collections.

Usage no npm install needed!

<script type="module">
  import tsGenericCollectionsLinq from 'https://cdn.skypack.dev/ts-generic-collections-linq';



TypeScript library provides generic, strongly-typed, queryable collections

The generic collections are:

  • List
  • Dictionary, SortedDictionary
  • Queue, RandomizedQueue
  • Stack

List, Dictionary collections implement interface IEnumerable<T>

export interface IEnumerable<T> {
    elementAt(index: number) : T;
    any(predicate?: (item: T)=> boolean) : boolean;
    all(predicate?: (item: T)=> boolean) : boolean;
    single(predicate?: (item: T)=> boolean) : T;
    first(predicate?: (item: T)=> boolean) : T;
    last(predicate?: (item: T)=> boolean) : T;
    singleOrDefault(predicate: (item: T)=> boolean) : T;    
    firstOrDefault(predicate: (item: T)=> boolean) : T;
    lastOrDefault(predicate: (item: T)=> boolean) : T;
    where(predicate: (item: T)=> boolean) : IEnumerable<T>;
    select<TResult>(predicate: (item: T)=> TResult) : IEnumerable<TResult>;
    selectMany<TResult>(predicate: (item: T)=> Array<TResult>) : IEnumerable<TResult>;
    join<TOuter, TMatch, TResult>(outer: IEnumerable<TOuter>, conditionInner: (item: T)=> TMatch, 
                                    conditionOuter: (item: TOuter)=> TMatch, select: (x: T, y:TOuter)=> TResult, leftJoin?: boolean) : IEnumerable<TResult>; 
    groupBy(predicate: (item: T) => Array<any>) : IEnumerable<IGroup<T>>; 
    orderBy(comparer: IComparer<T>) : IEnumerable<T>;
    distinct(comparer: IEqualityComparer<T>) : IEnumerable<T>;
    union(list: IEnumerable<T>) : IEnumerable<T>;
    reverse(): IEnumerable<T>;
    skip(no: number) : IEnumerable<T>;
    take(no: number) : IEnumerable<T>;
    sum(predicate: (item: T)=> number) : number;
    avg(predicate: (item: T)=> number) : number;
    min(predicate: (item: T)=> number) : number;
    max(predicate: (item: T)=> number) : number;
    count(predicate?: (item: T)=> boolean) : number;
    forEach(predicate: (item: T)=> void) : void;
    length: number;
    toArray() : Array<T>;
    asEnumerable() : IEnumerable<T>;


List implements interface IList<T>

export interface IList<T> extends IEnumerable<T> {
    add(item: T) : void;
    addRange(items: T[]) : void;
    remove(predicate: (item:T) => boolean) : void;
    removeAt(index: number) : void;
    clear() : void;

You can create queries like below

Import the library:

import { List, Dictionary } from 'ts-generic-collections-linq'

Below query gets the owners by the sex of their pets.

    let owners = new List<Owner>();

    let owner = new Owner();
    owner.id = 1;
    owner.name = "John Doe";

    owner = new Owner();
    owner.id = 2;
    owner.name = "Jane Doe";

    let pets = new List<Pet>();

    let pet = new Pet();
    pet.ownerId = 2;
    pet.name = "Sam";
    pet.sex = Sex.M;


    pet = new Pet();
    pet.ownerId = 1;
    pet.name = "Jenny";
    pet.sex = Sex.F;


    //query to get owners by the sex/gender of their pets
    let ownersByPetSex = owners.join(pets, owner => owner.id, pet => pet.ownerId, (x, y) => new OwnerPet(x,y))
                               .groupBy(x => [x.pet.sex])
                               .select(x =>  new OwnersByPetSex(x.groups[0], x.list.select(x => x.owner)));

    expect(ownersByPetSex.toArray().length === 2).toBeTruthy();

    expect(ownersByPetSex.toArray()[0].sex == Sex.F).toBeTruthy();
    expect(ownersByPetSex.toArray()[0].owners.length === 1).toBeTruthy();
    expect(ownersByPetSex.toArray()[0].owners.toArray()[0].name == "John Doe").toBeTruthy();

    expect(ownersByPetSex.toArray()[1].sex == Sex.M).toBeTruthy();
    expect(ownersByPetSex.toArray()[1].owners.length == 1).toBeTruthy();
    expect(ownersByPetSex.toArray()[1].owners.toArray()[0].name == "Jane Doe").toBeTruthy();                               

You can instantiate a List from JSON as shown below

    let jsonOwnerArray = '[{"id":1, "name": "John Doe"},{"id":2, "name": "Jane Doe"}]';

    let ownerArray: Owner[] = JSON.parse(jsonOwnerArray);

    let list = new List(ownerArray);

Entities for above example are

class Owner {
    id: number;
    name: string;

class Pet {
    ownerId: number;
    name: string;
    sex: Sex;

enum Sex {

class OwnerPet {
    owner: Owner;
    pet: Pet;

    constructor(owner: Owner, pet: Pet) {
        this.owner = owner;
        this.pet = pet;

class OwnersByPetSex {
    sex: Sex;
    owners: IEnumerable<Owner>;

    constructor(sex: Sex, owners: IEnumerable<Owner>) {
        this.sex = sex;
        this.owners = owners;


Dictionary, SortedDictionary implement IDictionary<TKey, TValue>

export interface IDictionary<TKey, TValue> extends IEnumerable<KeyValuePair<TKey, TValue>> {
    add(key: TKey, value: TValue) : void;
    addRange(items: KeyValuePair<TKey, TValue>[]) : void;
    remove(predicate: (item:KeyValuePair<TKey, TValue>) => boolean) : void;
    removeAt(index: number) : void;
    clear() : void;

    containsKey(key: TKey) : boolean;
    containsValue(value: TValue) : boolean;
    tryGetValue(key: TKey) : TValue;


  • sorted by Key
  • uses IComparer<TKey> to provide the sorted collection.


Queue, RandomizedQueue implement interface IQueue<T>

export interface IQueue<T> {    
    clear() : void;
    contains(item: T) : boolean;
    dequeue() : T;
    enqueue(item: T) : void;
    peek(): T;
    forEach(predicate: (item: T)=> void) : void;
    toArray(): Array<T>; 


  • enqueue to the end.
  • dequeue a random item.
  • peek (but not dequeue) a random item.
  • if you peek and then dequeue, the peeked item is dequeued.


Stack implements interface IStack<T>

export interface IStack<T> {
    clear() : void;
    contains(item: T) : boolean;
    pop() : T;
    push(item: T) : void;    
    peek(): T;
    forEach(predicate: (item: T)=> void) : void;
    toArray(): Array<T>;