# sidekicker

> TypeScript utilities, including deferred LINQ-to-Objects queries

Latest version **1.0.0** (published 2026-10-06) · MIT license · 0 weekly downloads

## Install

```sh
npm install sidekicker
pnpm add sidekicker
yarn add sidekicker
bun add sidekicker
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.0.0 |
| Published | 2026-10-06 |
| First published | 2018-12-08 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 628 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Allan Garcez |
| Maintainers | g4rcez |

## Links

- npm: https://www.npmjs.com/package/sidekicker
- npm.io page: https://npm.io/package/sidekicker

## Dependencies (1)

- [qs](https://npm.io/package/qs.md) ^6.16.0

## Recent versions

- 1.0.0 (latest) — 2026-10-06
- 0.1.10 — 2025-04-20
- 0.1.9 — 2024-11-08
- 0.1.8 — 2024-05-21
- 0.1.7 — 2024-05-12
- 0.1.6 — 2024-04-30
- 0.1.5 — 2024-04-30
- 0.1.4 — 2024-04-25
- 0.1.3 — 2024-04-24
- 0.1.2 — 2024-04-20
- 0.1.1 — 2024-04-20
- 0.0.28 — 2019-09-23
- 0.0.27 — 2019-07-16
- 0.0.26 — 2019-06-17
- 0.0.25 — 2019-06-17
- … 24 more at https://npm.io/package/sidekicker/versions

## README

# sidekicker

Sidekicker is a TypeScript utility library with a LINQ-style query API. See the [examples guide](docs/README.md) for runnable examples across the query and helper APIs.

## API

### LINQ to Objects

Sidekicker provides a LINQ-style query API over synchronous `Iterable<T>` sources:

```typescript
import { Linq } from "sidekicker";

const numbers = [0, 1, 2, 3, 4, 5, 6];
const evenSquares = new Linq(numbers).Where((number) => number % 2 === 0).Select((number) => number ** 2);

// No work is done until the query is enumerated.
const values = evenSquares.ToArray(); // [0, 4, 16, 36]
```

Sequence operators are deferred and return new queries without mutating the source query. Scalar operators execute immediately and short-circuit where possible. Each iteration re-enumerates a reusable source, so edits to an array are observed; a one-shot generator remains one-shot.

Indexed predicates and selectors receive a zero-based index:

```typescript
const thirdAndLater = new Linq(numbers).Where((_number, index) => index >= 2);
const indexed = thirdAndLater.Select((number, index) => ({ number, index }));
```

### Construction and composition

`Linq.From(source)`, `Linq.Empty<T>()`, `Linq.Range(start, count)`, and `Linq.Repeat(value, count)` create queries. Instance operators include `AsEnumerable`, `Append`, `Prepend`, `Concat`, `DefaultIfEmpty`, `Chunk`, and `Reverse`.

### Filtering and projection

`Where`, `OfType`, `Cast`, `Select`, `SelectMany`, `Take`, `Skip`, `TakeWhile`, `SkipWhile`, `TakeLast`, and `SkipLast` return deferred sequences.

```typescript
const names = new Linq([
    { name: "Ada", scores: [92, 98] },
    { name: "Grace", scores: [100] },
])
    .SelectMany(
        (person) => person.scores,
        (person, score) => ({ name: person.name, score }),
    )
    .Where((result) => result.score >= 95)
    .ToArray();
```

`OfType` and `Cast` take a TypeScript type guard because generic type parameters are erased at runtime. `OfType` skips values that fail the guard; `Cast` throws a `TypeError` on the first mismatch:

```typescript
const isString = (value: unknown): value is string => typeof value === "string";
const strings = new Linq<unknown>(["a", 1, "b"]).OfType(isString);
const checked = new Linq<unknown>(["a", 1, "b"]).Cast(isString); // Throws during enumeration.
```

### Ordering, grouping, and joins

`Order`, `OrderBy`, and `OrderByDescending` accept an optional comparator. Ordered queries support `ThenBy` and `ThenByDescending`; sorting is stable and evaluates each key selector once per element per enumeration.

`GroupBy` returns `Grouping<TKey, TElement>` values with a `Key`, `Count`, iteration, and `ToArray`. `Join` and `GroupJoin` preserve outer-sequence order and use a hash lookup for inner keys.

### Set and sequence operators

`Distinct`, `DistinctBy`, `Except`, `ExceptBy`, `Intersect`, `IntersectBy`, `Union`, `UnionBy`, `SequenceEqual`, and `Zip` use streaming iterators and `Set` lookups where appropriate. Set operators preserve first-sequence order and yield unique values. Set and grouping keys use JavaScript `Set`/`Map` semantics; object keys compare by identity.

### Terminal operators

`Aggregate`, `All`, `Any`, `Average`, `Contains`, `Count`, `LongCount`, `ElementAt`, `ElementAtOrDefault`, `First`, `FirstOrDefault`, `Last`, `LastOrDefault`, `Single`, `SingleOrDefault`, `Min`, `Max`, `MinBy`, and `MaxBy` execute immediately. Numeric aggregates accept a number selector or numeric property key where relevant. `First`, `Last`, `Single`, `Average`, `Min`, and `Max` throw `RangeError` when no required result exists; the `OrDefault` variants return `undefined` when there is no match.

### Materialization and execution

`ToArray` and `ToList` return arrays; `ToHashSet` returns a `Set`; `ToDictionary` and `ToMap` return `Map` instances; `ToLookup` returns `Map<TKey, TElement[]>`. `ToDictionary` throws on duplicate keys, while `ToMap` overwrites earlier values for duplicate keys.

`Where`, `Select`, `SelectMany`, `Take`, `Skip`, `TakeWhile`, `SkipWhile`, `Append`, `Prepend`, `Concat`, `Distinct`, and `Zip` can produce values without reading the whole source. `Take` therefore works with an infinite iterable. `Order`, `OrderBy`, `GroupBy`, `Reverse`, `Join`, and `GroupJoin` buffer or build lookups; set operators retain lookup state. Avoid fully enumerating unbounded sources with `ToArray`, `Count`, sorting, grouping, reversing, or joins.

The API targets synchronous LINQ-to-Objects. It does not implement `IQueryable`, SQL translation, expression trees, async iterables, or C# query-expression syntax.

### Array helpers

Sidekicker also exports optimized array helpers: `chunk`, `dict`, `distinct`, `partition`, `max`, `min`, `sum`, `arrayDiff`, `range`, `sort`, `multiSort`, and `Order`. The existing object-comparison helper remains available as `diff`.

### Data transformation helpers

`partition(iterable, predicate)` and `Linq.Partition(predicate)` traverse their source once and immediately return `[matching, nonMatching]` arrays. Root object utilities include `equals`, `merge`, `pick`, and `omit`; `merge` recursively combines object values into a new result, while `pick` and `omit` return shallow copies of own enumerable properties and are also available on `Objects`. `camelCase`, `snakeCase`, and `kebabCase` normalize common separators while preserving Unicode letters.

`debounce`, `throttle`, `sleep`, `negate`, and `formToJson` are exported from the package root; `formToJson` converts `FormData` fields into an object. `retry` requires a non-negative `retries` count of additional attempts after the initial call, and its callback receives `(signal, attempt)`. Optional `delay` (a number or `(attempt, error) => milliseconds`) and `shouldRetry(error, attempt)` settings control waits and error policy. An `AbortSignal` is passed to the callback and cancels pending waits.

### tryCatch

`tryCatch` wraps a synchronous or asynchronous function and returns an `Either`. Use `raise` to handle a specific error type.

```typescript
import { raise, tryCatch } from "sidekicker";

const parseJson = tryCatch(
    (text: string) => JSON.parse(text) as unknown,
    raise(SyntaxError, (error) => error.message),
);

const result = parseJson('{"active":true}');
if (result.isSuccess()) {
    console.log(result.success); // { active: true }
} else {
    console.error(result.error);
}
```

## Tooling and runtimes

The project uses Vite+ as its integrated toolchain: Oxlint for linting, Oxfmt for formatting, Vitest for tests, and `vp pack` (tsdown/Rolldown) for the library build. The toolchain requires Node.js `^22.18.0 || ^24.11.0 || >=26.0.0`; the repository pins Node.js 24.18.0 and npm 11.16.0 with Volta.

```sh
npm install
npm run check       # Oxfmt, Oxlint, and type-aware checks
npm run typecheck   # TypeScript 7 compiler
npm test
npm run test:coverage # Vitest V8 coverage with enforced thresholds
npm run build
npm run bench
```

`npm run bench` rebuilds the package, compiles an internal benchmark entry for `Dict`, verifies equivalent outputs, then compares the optimized library functions with their former map/reduce or copying implementations at small and large input sizes. It uses three warmups and seven alternating samples and reports medians without timing thresholds; treat the results as local diagnostics, not universal performance guarantees.

The build emits ESM (`dist/index.js`), CommonJS (`dist/index.cjs`), and format-matched declaration files. Deno and Bun both consume the same ESM build; separate runtime-specific bundles are unnecessary. `qs` remains an external runtime dependency and is resolved through `deno.json` for Deno.

The Deno build and test tasks invoke Vite+ under Node explicitly because the toolchain uses Node-specific APIs; Deno runs the shared ESM output.

```sh
npm run smoke:node

bun run build
npm run smoke:bun

deno task build
deno task test
deno task smoke
```

Run each smoke command after building for that runtime. `npm run smoke:node`, `npm run smoke:bun`, and `npm run smoke:deno` are convenience scripts; the Deno task is also available as `deno task smoke`.

---
_Source: https://npm.io/package/sidekicker · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
