TypeScript-first utility to check deep immutability in JavaScript objects
Tiny zero-dependency library to detect and assert deep immutability.
Works with plain objects, arrays, Maps, Sets, Dates, and nested structures.
Ships with full TypeScript support and ESM-only build.
- TypeScript-first — strong type guards like
value is DeepImmutable<T> - Deep immutability checks — recursive checks across nested structures
- Helpful errors —
assertImmutableshows the exact path of mutability - Zero dependencies — small, fast, tree-shakable
- Modern packaging — ESM, Node 18+, Deno, Bun
npm install is-deep-immutableimport{isDeepImmutable,assertImmutable}from'is-deep-immutable';constdata={users: [{id: 1,name: 'Alice'}],metadata: newMap([['version','1.0.0']]),tags: newSet(['production'])};// Check if deeply immutableconsole.log(isDeepImmutable(data));// false// Manually freeze for testingconstfrozen=Object.freeze({users: Object.freeze(data.users.map(u=>Object.freeze(u))),metadata: Object.freeze(data.metadata),tags: Object.freeze(data.tags)});console.log(isDeepImmutable(frozen));// true// Assert immutability (throws if not)assertImmutable(frozen);// ✓ passesassertImmutable(data);// ✗ throws with detailed pathType guard that checks if a value is deeply immutable. Returns true for primitives and recursively frozen objects.
isDeepImmutable(42);// trueisDeepImmutable('hello');// true isDeepImmutable({});// falseisDeepImmutable(Object.freeze({}));// trueAsserts that a value is deeply immutable. Throws with the exact path of mutability if not.
assertImmutable({mutable: true});// Error: Value is not immutable at path "root": Object is not frozenassertImmutable({nested: {mutable: true}});// Error: Value is not immutable at path "nested": Object is not frozenFull TypeScript support with the DeepImmutable<T> utility type:
typeDeepImmutable<T>=Textends(infer U)[]
? ReadonlyArray<DeepImmutable<U>>
: TextendsMap<infer K, infer V>
? ReadonlyMap<DeepImmutable<K>,DeepImmutable<V>>
: TextendsSet<infer U>
? ReadonlySet<DeepImmutable<U>>
: Textendsobject
? {readonly[KinkeyofT]: DeepImmutable<T[K]>}
: T;- Primitives:
string,number,boolean,null,undefined,symbol,bigint - Objects: Plain objects with recursive property checking
- Arrays: Recursive element checking
- Maps: Key and value immutability checking
- Sets: Element immutability checking
- Dates: Treated as immutable when frozen
- Circular references: Handled safely without infinite recursion
MIT