typescript 25 lines · 5 steps

Splitting work into sequential batches in TypeScript

A generic chunk helper feeds an async runner that processes batches one at a time.

Explained by highlit
1export function chunk<T>(items: readonly T[], size: number): T[][] {
2 if (size <= 0 || !Number.isInteger(size)) {
3 throw new RangeError(`chunk size must be a positive integer, got ${size}`);
4 }
5 
6 const batches: T[][] = [];
7 for (let i = 0; i < items.length; i += size) {
8 batches.push(items.slice(i, i + size));
9 }
10 return batches;
11}
12 
13export async function processInBatches<T, R>(
14 items: readonly T[],
15 size: number,
16 handler: (batch: T[], index: number) => Promise<R>,
17): Promise<R[]> {
18 const batches = chunk(items, size);
19 const results: R[] = [];
20 
21 for (let index = 0; index < batches.length; index++) {
22 results.push(await handler(batches[index], index));
23 }
24 return results;
25}
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1Validating inputs up front turns a silent infinite loop into a clear, immediate error.
  2. 2Generic type parameters let one helper slice arrays of any element type safely.
  3. 3Awaiting inside a sequential loop processes batches one at a time instead of all at once.

Related explainers

typescript
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';
import localeDe from '@angular/common/locales/de';

Locale-aware bootstrapping in Angular

i18n localization dependency-injection
Intermediate 8 steps
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
 

Validating env config at boot in NestJS

configuration schema-validation environment-variables
Intermediate 8 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { InjectRepository } from '@nestjs/typeorm';

A cache-aside country lookup in NestJS

cache-aside dependency-injection batch-lookup
Intermediate 8 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core';
 
interface Preferences {
  theme: 'light' | 'dark';

A signal-based preferences store in Angular

signals state-management persistence
Intermediate 7 steps
typescript
import { useEffect, useState } from "react";
 
interface Section {
  id: string;

Building a scroll-spy hook in React

custom-hooks intersectionobserver dom-observation
Intermediate 8 steps
python
import secrets
 
from django.contrib.auth import authenticate, login
from django.core.cache import cache

Two-factor login with OTP in Django

two-factor-auth one-time-passwords caching
Intermediate 9 steps

Share this explainer

Here's the card — post it anywhere.

Splitting work into sequential batches in TypeScript — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code