Immutable.js provides persistent immutable data structures for JavaScript including List, Stack, Map, OrderedMap, Set, OrderedSet and Record. Built using structural sharing via hash map tries and vector tries, these collections are highly efficient on modern JavaScript VMs by minimizing data copying. The library enables functional programming patterns with a JavaScript-first API, supports lazy sequences for efficient method chaining, provides advanced equality checking that treats collections as values, and includes batching mutations for performance optimization.
npm install immutableimport { List, Map, Set, Stack, OrderedMap, OrderedSet, Record, Seq, Range, Repeat, fromJS, is } from 'immutable';const { List, Map, Set, Stack, OrderedMap, OrderedSet, Record, Seq, Range, Repeat, fromJS, is } = require('immutable');Default import:
import Immutable from 'immutable';
const { List, Map, Set } = Immutable;interface Collection<K, V> {
size: number;
equals(other: unknown): boolean;
hashCode(): number;
get(key: K, notSetValue?: V): V | undefined;
has(key: K): boolean;
includes(value: V): boolean;
contains(value: V): boolean; // Alias for includes
first(notSetValue?: V): V | undefined;
last(notSetValue?: V): V | undefined;
getIn(keyPath: Iterable<unknown>, notSetValue?: unknown): unknown;
hasIn(keyPath: Iterable<unknown>): boolean;
setIn(keyPath: Iterable<unknown>, value: unknown): this;
updateIn(keyPath: Iterable<unknown>, updater: (value: unknown) => unknown): this;
deleteIn(keyPath: Iterable<unknown>): this;
removeIn(keyPath: Iterable<unknown>): this; // Alias for deleteIn
mergeIn(keyPath: Iterable<unknown>, ...collections: unknown[]): this;
mergeDeepIn(keyPath: Iterable<unknown>, ...collections: unknown[]): this;
toJS(): unknown;
toJSON(): unknown;
toArray(): unknown[];
toObject(): { [key: string]: V };
toMap(): Map<K, V>;
toOrderedMap(): OrderedMap<K, V>;
toSet(): Set<V>;
toOrderedSet(): OrderedSet<V>;
toList(): List<V>;
toStack(): Stack<V>;
toSeq(): Seq<K, V>;
toKeyedSeq(): Seq.Keyed<K, V>;
toIndexedSeq(): Seq.Indexed<V>;
toSetSeq(): Seq.Set<V>;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
keySeq(): Seq.Indexed<K>;
valueSeq(): Seq.Indexed<V>;
entrySeq(): Seq.Indexed<[K, V]>;
map<M>(mapper: (value: V, key: K, iter: this) => M, context?: unknown): Collection<K, M>;
filter(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): this;
filterNot(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): this;
partition(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): [this, this];
reverse(): this;
sort(comparator?: Comparator<V>): this;
sortBy<C>(comparatorValueMapper: (value: V, key: K, iter: this) => C, comparator?: Comparator<C>): this;
groupBy<G>(grouper: (value: V, key: K, iter: this) => G, context?: unknown): Map<G, this>;
reduce<R>(reducer: (reduction: R, value: V, key: K, iter: this) => R, initialReduction: R, context?: unknown): R;
reduceRight<R>(reducer: (reduction: R, value: V, key: K, iter: this) => R, initialReduction: R, context?: unknown): R;
every(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): boolean;
some(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): boolean;
join(separator?: string): string;
isEmpty(): boolean;
count(predicate?: (value: V, key: K, iter: this) => boolean, context?: unknown): number;
countBy<G>(grouper: (value: V, key: K, iter: this) => G, context?: unknown): Map<G, number>;
find(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown, notSetValue?: V): V | undefined;
findLast(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown, notSetValue?: V): V | undefined;
findEntry(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown, notSetValue?: V): [K, V] | undefined;
findLastEntry(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown, notSetValue?: V): [K, V] | undefined;
findKey(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): K | undefined;
findLastKey(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): K | undefined;
keyOf(searchValue: V): K | undefined;
lastKeyOf(searchValue: V): K | undefined;
max(comparator?: Comparator<V>): V | undefined;
maxBy<C>(comparatorValueMapper: (value: V, key: K, iter: this) => C, comparator?: Comparator<C>): V | undefined;
min(comparator?: Comparator<V>): V | undefined;
minBy<C>(comparatorValueMapper: (value: V, key: K, iter: this) => C, comparator?: Comparator<C>): V | undefined;
isSubset(iter: Iterable<V>): boolean;
isSuperset(iter: Iterable<V>): boolean;
forEach(sideEffect: (value: V, key: K, iter: this) => void, context?: unknown): number;
slice(begin?: number, end?: number): this;
rest(): this;
butLast(): this;
skip(amount: number): this;
skipLast(amount: number): this;
skipWhile(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): this;
skipUntil(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): this;
take(amount: number): this;
takeLast(amount: number): this;
takeWhile(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): this;
takeUntil(predicate: (value: V, key: K, iter: this) => boolean, context?: unknown): this;
concat(...valuesOrCollections: Array<unknown>): this;
flatten(depth?: number): Collection<unknown, unknown>;
flatMap<M>(mapper: (value: V, key: K, iter: this) => Iterable<M>, context?: unknown): Collection<number, M>;
withMutations(mutator: (mutable: this) => unknown): this;
asMutable(): this;
asImmutable(): this;
wasAltered(): boolean;
[Symbol.iterator](): IterableIterator<[K, V]>;
}interface ValueObject {
equals(other: unknown): boolean;
hashCode(): number;
}type Comparator<T> = (valueA: T, valueB: T) => number;enum PairSorting {
LeftThenRight = -1,
RightThenLeft = 1
}import { List, Map, Set, fromJS } from 'immutable';
// Create from arrays and objects
const list = List([1, 2, 3]);
const map = Map({ a: 1, b: 2 });
const set = Set([1, 2, 3, 2]); // [1, 2, 3]
// Convert JavaScript data structures
const immutableData = fromJS({
list: [1, 2, 3],
map: { a: 1, b: 2 }
});import { List, Map } from 'immutable';
const list = List([1, 2, 3]);
const newList = list.push(4).set(0, 10); // [10, 2, 3, 4]
const map = Map({ a: 1, b: 2 });
const newMap = map.set('c', 3).delete('a'); // { b: 2, c: 3 }import { List, is } from 'immutable';
const list1 = List([1, 2, 3]);
const list2 = List([1, 2, 3]);
console.log(list1 === list2); // false (reference equality)
console.log(is(list1, list2)); // true (value equality)
console.log(list1.equals(list2)); // true (value equality)Core immutable data structures with persistent modifications and structural sharing.
class List<T> implements Collection<number, T> {
static <T>(collection?: Iterable<T>): List<T>;
static of<T>(...values: T[]): List<T>;
static isList(maybeList: unknown): maybeList is List<unknown>;
size: number;
get(index: number, notSetValue?: T): T | undefined;
set(index: number, value: T): List<T>;
push(...values: T[]): List<T>;
pop(): List<T>;
unshift(...values: T[]): List<T>;
shift(): List<T>;
insert(index: number, value: T): List<T>;
delete(index: number): List<T>;
}class Map<K, V> implements Collection<K, V> {
static <K, V>(collection?: Iterable<[K, V]> | {[key: string]: V}): Map<K, V>;
static isMap(maybeMap: unknown): maybeMap is Map<unknown, unknown>;
size: number;
get(key: K, notSetValue?: V): V | undefined;
has(key: K): boolean;
set(key: K, value: V): Map<K, V>;
delete(key: K): Map<K, V>;
merge(...collections: Array<Iterable<[K, V]> | {[key: string]: V}>): Map<K, V>;
}class Set<T> implements Collection<T, T> {
static <T>(collection?: Iterable<T>): Set<T>;
static of<T>(...values: T[]): Set<T>;
static isSet(maybeSet: unknown): maybeSet is Set<unknown>;
size: number;
has(value: T): boolean;
add(value: T): Set<T>;
delete(value: T): Set<T>;
union(...collections: Iterable<T>[]): Set<T>;
intersect(...collections: Iterable<T>[]): Set<T>;
subtract(...collections: Iterable<T>[]): Set<T>;
}class OrderedMap<K, V> implements Collection<K, V> {
static <K, V>(collection?: Iterable<[K, V]> | {[key: string]: V}): OrderedMap<K, V>;
static isOrderedMap(maybeOrderedMap: unknown): maybeOrderedMap is OrderedMap<unknown, unknown>;
size: number;
get(key: K, notSetValue?: V): V | undefined;
has(key: K): boolean;
set(key: K, value: V): OrderedMap<K, V>;
delete(key: K): OrderedMap<K, V>;
merge(...collections: Array<Iterable<[K, V]> | {[key: string]: V}>): OrderedMap<K, V>;
}class OrderedSet<T> implements Collection<T, T> {
static <T>(collection?: Iterable<T>): OrderedSet<T>;
static of<T>(...values: T[]): OrderedSet<T>;
static isOrderedSet(maybeOrderedSet: unknown): maybeOrderedSet is OrderedSet<unknown>;
size: number;
has(value: T): boolean;
add(value: T): OrderedSet<T>;
delete(value: T): OrderedSet<T>;
union(...collections: Iterable<T>[]): OrderedSet<T>;
}class Stack<T> implements Collection<number, T> {
static <T>(collection?: Iterable<T>): Stack<T>;
static of<T>(...values: T[]): Stack<T>;
static isStack(maybeStack: unknown): maybeStack is Stack<unknown>;
size: number;
get(index: number, notSetValue?: T): T | undefined;
peek(): T | undefined;
push(...values: T[]): Stack<T>;
pop(): Stack<T>;
unshift(...values: T[]): Stack<T>;
shift(): Stack<T>;
}Lazy sequences for efficient chaining of operations without creating intermediate collections.
abstract class Seq<K, V> implements Collection<K, V> {
static <K, V>(collection: Collection<K, V>): Seq<K, V>;
static isSeq(maybeSeq: unknown): maybeSeq is Seq<unknown, unknown>;
size: number | undefined;
cacheResult(): Seq<K, V>;
}function Range(start?: number, end?: number, step?: number): Seq.Indexed<number>;function Repeat<T>(value: T, times?: number): Seq.Indexed<T>;Functional utilities for working with immutable data structures.
function fromJS<T>(jsValue: T, reviver?: (key: string | number, sequence: Collection.Indexed<unknown> | Collection.Keyed<string, unknown>, path?: Array<string | number>) => unknown): T extends ReadonlyArray<infer U> ? List<U> : T extends object ? Map<string, unknown> : T;function is(valueA: unknown, valueB: unknown): boolean;function get<K, V>(collection: Collection<K, V>, key: K, notSetValue?: V): V | undefined;
function has<K, V>(collection: Collection<K, V>, key: K): boolean;
function set<K, V>(collection: Collection<K, V>, key: K, value: V): Collection<K, V>;
function remove<K, V>(collection: Collection<K, V>, key: K): Collection<K, V>;
function update<K, V>(collection: Collection<K, V>, key: K, updater: (value: V) => V): Collection<K, V>;
function update<K, V>(collection: Collection<K, V>, key: K, notSetValue: V, updater: (value: V) => V): Collection<K, V>;function getIn<C>(collection: C, keyPath: Iterable<unknown>, notSetValue?: unknown): unknown;
function hasIn<C>(collection: C, keyPath: Iterable<unknown>): boolean;
function setIn<C>(collection: C, keyPath: Iterable<unknown>, value: unknown): C;
function removeIn<C>(collection: C, keyPath: Iterable<unknown>): C;
function updateIn<C>(collection: C, keyPath: Iterable<unknown>, updater: (value: unknown) => unknown): C;
function updateIn<C>(collection: C, keyPath: Iterable<unknown>, notSetValue: unknown, updater: (value: unknown) => unknown): C;function merge<C>(collection: C, ...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>): C;
function mergeWith<C>(merger: (oldVal: unknown, newVal: unknown, key: unknown) => unknown, collection: C, ...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>): C;
function mergeDeep<C>(collection: C, ...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>): C;
function mergeDeepWith<C>(merger: (oldVal: unknown, newVal: unknown, key: unknown) => unknown, collection: C, ...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>): C;Type guards, hash functions, and Record factory for creating typed immutable objects.
function hash(value: unknown): number;function isImmutable(maybeImmutable: unknown): maybeImmutable is Collection<unknown, unknown>;
function isCollection(maybeCollection: unknown): maybeCollection is Collection<unknown, unknown>;
function isKeyed(maybeKeyed: unknown): maybeKeyed is Collection.Keyed<unknown, unknown>;
function isIndexed(maybeIndexed: unknown): maybeIndexed is Collection.Indexed<unknown>;
function isAssociative(maybeAssociative: unknown): maybeAssociative is Collection.Keyed<unknown, unknown> | Collection.Indexed<unknown>;
function isOrdered(maybeOrdered: unknown): boolean;
function isValueObject(maybeValue: unknown): maybeValue is { equals(other: unknown): boolean; hashCode(): number };
function isSeq(maybeSeq: unknown): maybeSeq is Seq<unknown, unknown>;
function isList(maybeList: unknown): maybeList is List<unknown>;
function isMap(maybeMap: unknown): maybeMap is Map<unknown, unknown>;
function isOrderedMap(maybeOrderedMap: unknown): maybeOrderedMap is OrderedMap<unknown, unknown>;
function isStack(maybeStack: unknown): maybeStack is Stack<unknown>;
function isSet(maybeSet: unknown): maybeSet is Set<unknown>;
function isOrderedSet(maybeOrderedSet: unknown): maybeOrderedSet is OrderedSet<unknown>;
function isRecord(maybeRecord: unknown): maybeRecord is Record<{[key: string]: unknown}>;
function isPlainObject(maybeObject: unknown): maybeObject is {[key: string]: unknown};const version: string;
const PairSorting: {
LeftThenRight: -1;
RightThenLeft: 1;
};interface RecordFactory<TProps> {
<Ks extends keyof TProps>(values?: Partial<Pick<TProps, Ks>> | Iterable<[Ks, TProps[Ks]]>): Record<TProps> & Readonly<TProps>;
displayName: string;
}function Record<TProps>(defaultValues: TProps, name?: string): RecordFactory<TProps>;