The functional API provides utility functions for working with immutable data structures in a functional programming style. These functions work with any Collection and provide an alternative to method chaining.
import {
fromJS, is,
get, has, set, remove, update,
getIn, hasIn, setIn, removeIn, updateIn,
merge, mergeWith, mergeDeep, mergeDeepWith
} from 'immutable';Converts plain JavaScript objects and arrays to Immutable collections recursively.
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;jsValue: JavaScript value to convertreviver (optional): Function to transform values during conversionimport { fromJS } from 'immutable';
// Basic conversion
const data = fromJS({
users: [
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false }
],
settings: {
theme: 'dark',
notifications: true
}
});
// Results in:
// Map {
// "users" => List [
// Map { "id" => 1, "name" => "Alice", "active" => true },
// Map { "id" => 2, "name" => "Bob", "active" => false }
// ],
// "settings" => Map {
// "theme" => "dark",
// "notifications" => true
// }
// }
// With custom reviver
const withReviver = fromJS([1, 2, 3, 4], (key, value, path) => {
return value.toOrderedSet();
});
// Results in OrderedSet { 1, 2, 3, 4 }
// Complex reviver example
const customData = fromJS({
timestamp: '2023-01-01T00:00:00Z',
tags: ['important', 'urgent'],
metadata: { priority: 'high' }
}, (key, value) => {
if (key === 'timestamp') {
return new Date(value);
}
if (key === 'tags') {
return value.toOrderedSet();
}
return value;
});Performs deep value equality comparison using Immutable's equality semantics.
function is(valueA: unknown, valueB: unknown): boolean;import { is, List, Map } from 'immutable';
// Primitive values
console.log(is(1, 1)); // true
console.log(is(NaN, NaN)); // true (unlike ===)
console.log(is(0, -0)); // true (unlike Object.is)
// Collections
const list1 = List([1, 2, 3]);
const list2 = List([1, 2, 3]);
const list3 = List([1, 2, 4]);
console.log(is(list1, list2)); // true (value equality)
console.log(list1 === list2); // false (reference equality)
console.log(is(list1, list3)); // false (different values)
// Nested structures
const map1 = Map({ a: List([1, 2]), b: 3 });
const map2 = Map({ a: List([1, 2]), b: 3 });
console.log(is(map1, map2)); // true
// Custom value objects
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
valueOf() {
return `${this.x},${this.y}`;
}
}
const point1 = new Point(1, 2);
const point2 = new Point(1, 2);
console.log(is(point1, point2)); // true (uses valueOf)Gets a value from a collection.
function get<K, V>(collection: Collection<K, V>, key: K, notSetValue?: V): V | undefined;Checks if a collection contains a key.
function has<K, V>(collection: Collection<K, V>, key: K): boolean;Sets a value in a collection, returning a new collection.
function set<K, V>(collection: Collection<K, V>, key: K, value: V): Collection<K, V>;Removes a key from a collection, returning a new collection.
function remove<K, V>(collection: Collection<K, V>, key: K): Collection<K, V>;Updates a value in a collection using an updater function.
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>;import { Map, List, get, has, set, remove, update } from 'immutable';
const map = Map({ a: 1, b: 2, c: 3 });
const list = List([10, 20, 30]);
// get
console.log(get(map, 'a')); // 1
console.log(get(list, 1)); // 20
console.log(get(map, 'x', 'default')); // 'default'
// has
console.log(has(map, 'b')); // true
console.log(has(list, 5)); // false
// set
const newMap = set(map, 'd', 4); // Map { a: 1, b: 2, c: 3, d: 4 }
const newList = set(list, 1, 25); // List [ 10, 25, 30 ]
// remove
const removedMap = remove(map, 'b'); // Map { a: 1, c: 3 }
const removedList = remove(list, 0); // List [ 20, 30 ]
// update
const updatedMap = update(map, 'a', val => val * 10); // Map { a: 10, b: 2, c: 3 }
const updatedList = update(list, 0, val => val + 5); // List [ 15, 20, 30 ]
// update with notSetValue
const updatedNew = update(map, 'x', 0, val => val + 1); // Map { a: 1, b: 2, c: 3, x: 1 }Gets a value from a nested collection structure.
function getIn<C>(collection: C, keyPath: Iterable<unknown>, notSetValue?: unknown): unknown;Checks if a nested collection structure contains a key path.
function hasIn<C>(collection: C, keyPath: Iterable<unknown>): boolean;Sets a value in a nested collection structure.
function setIn<C>(collection: C, keyPath: Iterable<unknown>, value: unknown): C;Removes a value from a nested collection structure.
function removeIn<C>(collection: C, keyPath: Iterable<unknown>): C;Updates a value in a nested collection structure using an updater function.
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;import { fromJS, getIn, hasIn, setIn, removeIn, updateIn } from 'immutable';
const nested = fromJS({
users: [
{
id: 1,
profile: {
name: 'Alice',
settings: { theme: 'dark', lang: 'en' }
}
},
{
id: 2,
profile: {
name: 'Bob',
settings: { theme: 'light', lang: 'es' }
}
}
],
config: {
app: { version: '1.0.0', debug: true }
}
});
// getIn
console.log(getIn(nested, ['users', 0, 'profile', 'name'])); // 'Alice'
console.log(getIn(nested, ['config', 'app', 'version'])); // '1.0.0'
console.log(getIn(nested, ['users', 0, 'missing'], 'default')); // 'default'
// hasIn
console.log(hasIn(nested, ['users', 1, 'profile', 'settings', 'theme'])); // true
console.log(hasIn(nested, ['users', 2])); // false
// setIn - creates intermediate structure if needed
const updated1 = setIn(nested, ['users', 0, 'profile', 'email'], 'alice@example.com');
const updated2 = setIn(nested, ['new', 'deep', 'path'], 'value');
// removeIn
const removed = removeIn(nested, ['users', 0, 'profile', 'settings', 'lang']);
// updateIn
const updated3 = updateIn(nested, ['config', 'app', 'version'], version =>
version.split('.').map(n => parseInt(n)).join('.')
);
// updateIn with notSetValue
const updated4 = updateIn(nested, ['users', 0, 'profile', 'loginCount'], 0, count => count + 1);
// Complex path operations
const userPath = ['users', 1, 'profile', 'settings'];
const updatedSettings = updateIn(nested, userPath, settings =>
settings.set('notifications', true).set('theme', 'auto')
);Shallow merges collections or objects into a collection.
function merge<C>(collection: C, ...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>): C;Shallow merges with a custom merger function for conflicting keys.
function mergeWith<C>(
merger: (oldVal: unknown, newVal: unknown, key: unknown) => unknown,
collection: C,
...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>
): C;Deep merges collections or objects into a collection.
function mergeDeep<C>(collection: C, ...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>): C;Deep merges with a custom merger function for conflicting values.
function mergeDeepWith<C>(
merger: (oldVal: unknown, newVal: unknown, key: unknown) => unknown,
collection: C,
...collections: Array<Partial<C> | Iterable<[unknown, unknown]> | {[key: string]: unknown}>
): C;import { Map, fromJS, merge, mergeWith, mergeDeep, mergeDeepWith } from 'immutable';
const base = Map({
a: 1,
b: 2,
nested: Map({ x: 10, y: 20 })
});
// merge - shallow
const merged1 = merge(base, { b: 3, c: 4 });
// Map { a: 1, b: 3, c: 4, nested: Map { x: 10, y: 20 } }
const merged2 = merge(base, { nested: Map({ z: 30 }) });
// Map { a: 1, b: 2, nested: Map { z: 30 } } - nested is replaced, not merged
// mergeWith - custom conflict resolution
const mergedWith = mergeWith(
(oldVal, newVal, key) => {
if (key === 'b') return oldVal + newVal; // Sum for key 'b'
return newVal;
},
base,
{ b: 3, c: 4 }
);
// Map { a: 1, b: 5, c: 4, nested: Map { x: 10, y: 20 } }
// mergeDeep - recursive merging
const deepBase = fromJS({
user: {
profile: { name: 'Alice', age: 25 },
settings: { theme: 'dark', lang: 'en' }
},
app: { version: '1.0' }
});
const deepMerged = mergeDeep(deepBase, {
user: {
profile: { age: 26, email: 'alice@example.com' },
settings: { notifications: true }
},
app: { debug: true }
});
// Deeply merges all nested structures
// mergeDeepWith - custom deep conflict resolution
const deepMergedWith = mergeDeepWith(
(oldVal, newVal, key) => {
if (key === 'age' && typeof oldVal === 'number' && typeof newVal === 'number') {
return Math.max(oldVal, newVal); // Keep higher age
}
return newVal;
},
deepBase,
{
user: {
profile: { age: 20, status: 'active' }
}
}
);
// Multiple source merging
const multi = merge(
Map({ a: 1 }),
{ b: 2 },
Map([['c', 3]]),
{ d: 4 }
);
// Map { a: 1, b: 2, c: 3, d: 4 }The functional API enables clean composition and piping:
import { Map, get, set, update, updateIn, mergeDeep } from 'immutable';
const state = Map({
user: Map({
id: 1,
profile: Map({ name: 'Alice', score: 100 })
}),
ui: Map({ theme: 'light' })
});
// Function composition
const incrementScore = (state) =>
updateIn(state, ['user', 'profile', 'score'], score => score + 10);
const setTheme = (theme) => (state) =>
set(state, 'ui', get(state, 'ui').set('theme', theme));
const addNotification = (message) => (state) =>
update(state, 'notifications', List(), notifications =>
notifications.push(Map({ message, timestamp: Date.now() }))
);
// Compose operations
const newState = [
incrementScore,
setTheme('dark'),
addNotification('Score updated!')
].reduce((state, fn) => fn(state), state);
// Utility function for deep updates
const deepUpdate = (keyPath, updater) => (collection) =>
updateIn(collection, keyPath, updater);
// Pipeline of operations
const pipeline = [
deepUpdate(['user', 'profile', 'name'], name => name.toUpperCase()),
deepUpdate(['user', 'profile', 'score'], score => Math.min(score, 1000)),
(state) => mergeDeep(state, {
user: { lastUpdate: new Date().toISOString() }
})
];
const finalState = pipeline.reduce((state, fn) => fn(state), state);