Effect collection patterns - Arrays, Chunks, Records, HashMaps. Use when choosing collection types or working with transformations.
Installation
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Effect collection patterns - Arrays, Chunks, Records, HashMaps. Use when choosing collection types or working with transformations.
user-invocable
false
Effect Collections
Use native arrays with Effect's Array module for most transformations. Reserve Chunk for repeated concatenation and Streams. Prefer native objects with Record module for string-keyed data. Choose HashMap only for complex keys or value-based equality.
Array Module: Native Arrays + Effect Utilities
Effect's Array module operates on standard JavaScript arrays—zero runtime overhead with composable operations that understand Option/Either:
Chunk<T> is optimized specifically for amortizing repeated concatenation cost—O(1) amortized vs O(n) for native arrays. Essential when building collections incrementally; slower than arrays for everything else.
Benchmark: Building 100,000 elements via repeated concat: ~52s (native array) vs ~10.7ms (Chunk)—~5000x faster.
Start with native types + Effect's Array/Record modules
Introduce Chunk only for concat performance issues or Streams
Introduce HashMap only for non-string keys or value equality
Convert at boundaries: native types at API edges
Readonly Types
Effect provides type aliases that signal immutability at the type level. Use these in function signatures and type definitions.
Type Equivalences
Effect Type
Equivalent To
Notes
Array.Array<T>
ReadonlyArray<T>
Same type, re-exported by Effect
readonly T[]
ReadonlyArray<T>
TypeScript shorthand
Record.ReadonlyRecord<K,V>
{ readonly [P in K]: V }
Effect's readonly record type
Usage Guidelines
import { Array, Record } from"effect";
// Prefer Effect's type aliases in signaturesinterfaceUserState {
readonlyusers: Array.Array<User>; // = ReadonlyArray<User>readonlybyId: Record.ReadonlyRecord<string, User>; // readonly string-keyed
}
// Function signatures signal immutabilityconst processUsers = (users: Array.Array<User>): Array.Array<ProcessedUser> =>
Array.map(users, transform);
// All three are equivalent for arrays:type A = Array.Array<string>; // Effect alias (preferred)type B = ReadonlyArray<string>; // TypeScript built-intype C = readonlystring[]; // TypeScript shorthand
Immutable by Design
Chunk and HashMap are already immutable—no readonly variants needed:
Replace unsafe index access with Array.head/Array.get
// Before: unsafe access even after length checkif (refs.length > 0) {
const ref = refs[0]; // still typed as T | undefined
}
// After: safe access with Optionconst ref = Array.head(refs); // Option<T>const result = Option.match(ref, {
onNone: () =>handleEmpty(),
onSome: (r) =>process(r),
});
// For arbitrary indexconst third = Array.get(items, 2); // Option<T>
Fix double-call anti-pattern with Array.partition
// Before: calls getAgentById twice per elementconst validIds = args.agent.filter((id) =>Option.isSome(getAgentById(id)));
const invalidIds = args.agent.filter((id) =>Option.isNone(getAgentById(id)));
// After: single pass with partitionconst [invalidIds, validIds] = Array.partition(args.agent, (id) =>Option.isSome(getAgentById(id)));
Replace .map().filter().map() with Array.filterMap
// Before: multiple passesconst indices = options
.map((opt, i) => (opt.selected ? i : undefined))
.filter((i) => i !== undefined)
.map((i) => i!);
// After: single pass with Optionconst indices = Array.filterMap(options, (opt, i) =>
opt.selected ? Option.some(i) : Option.none(),
);
Replace array destructuring with Effect utilities
// Before: destructuring loses type safetyconst [resolver, ...rest] = remaining;
if (!resolver) thrownewError("Empty");
// After: explicit head/tail with NonEmpty guaranteesconst head = Array.head(remaining);
const tail = Array.tail(remaining);
// Or use NonEmpty variants when you know the array isn't emptyconst head = Array.headNonEmpty(remaining); // T (not Option<T>)const tail = Array.tailNonEmpty(remaining); // Array<T>
Effect Collections Checklist
Default to native types — Arrays and objects with Effect modules
Chunk for concat only — Building incrementally or working with Streams
HashMap for complex keys — Non-string keys or value-based equality
Convert at boundaries — Native types for external APIs, JSON
Use Array utilities — filterMap, getSomes, separate for Option/Either
Use Record utilities — get, filterMap, collect for object transforms
Readonly types — Array.Array<T> and Record.ReadonlyRecord<K,V> in signatures
Safe access — Array.head, Array.get, Array.findFirst instead of [0], .find()
Single-pass operations — Array.partition instead of double filter, Array.filterMap instead of map/filter chains