Immutable persistent data collections for Javascript which increase efficiency and simplicity.

Overview

Immutable collections for JavaScript

Build Status Join the chat at https://gitter.im/immutable-js/Lobby

Immutable data cannot be changed once created, leading to much simpler application development, no defensive copying, and enabling advanced memoization and change detection techniques with simple logic. Persistent data presents a mutative API which does not update the data in-place, but instead always yields new updated data.

Immutable.js provides many Persistent Immutable data structures including: List, Stack, Map, OrderedMap, Set, OrderedSet and Record.

These data structures are highly efficient on modern JavaScript VMs by using structural sharing via hash maps tries and vector tries as popularized by Clojure and Scala, minimizing the need to copy or cache data.

Immutable.js also provides a lazy Seq, allowing efficient chaining of collection methods like map and filter without creating intermediate representations. Create some Seq with Range and Repeat.

Want to hear more? Watch the presentation about Immutable.js:

Getting started

Install immutable using npm.

npm install immutable

Then require it into any module.

const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);
map1.get('b') + " vs. " + map2.get('b'); // 2 vs. 50

Browser

Immutable.js has no dependencies, which makes it predictable to include in a Browser.

It's highly recommended to use a module bundler like webpack, rollup, or browserify. The immutable npm module works without any additional consideration. All examples throughout the documentation will assume use of this kind of tool.

Alternatively, Immutable.js may be directly included as a script tag. Download or link to a CDN such as CDNJS or jsDelivr.

Use a script tag to directly add Immutable to the global scope:

<script src="immutable.min.js"></script>
<script>
  var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
  var map2 = map1.set('b', 50);
  map1.get('b'); // 2
  map2.get('b'); // 50
</script>

Or use an AMD-style loader (such as RequireJS):

require(['./immutable.min.js'], function (Immutable) {
  var map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
  var map2 = map1.set('b', 50);
  map1.get('b'); // 2
  map2.get('b'); // 50
});

Flow & TypeScript

Use these Immutable collections and sequences as you would use native collections in your Flowtype or TypeScript programs while still taking advantage of type generics, error detection, and auto-complete in your IDE.

Installing immutable via npm brings with it type definitions for Flow (v0.55.0 or higher) and TypeScript (v2.1.0 or higher), so you shouldn't need to do anything at all!

Using TypeScript with Immutable.js v4

Immutable.js type definitions embrace ES2015. While Immutable.js itself supports legacy browsers and environments, its type definitions require TypeScript's 2015 lib. Include either "target": "es2015" or "lib": "es2015" in your tsconfig.json, or provide --target es2015 or --lib es2015 to the tsc command.

const { Map } = require("immutable");
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);
map1.get('b') + " vs. " + map2.get('b'); // 2 vs. 50

Using TypeScript with Immutable.js v3 and earlier:

Previous versions of Immutable.js include a reference file which you can include via relative path to the type definitions at the top of your file.

///<reference path='./node_modules/immutable/dist/immutable.d.ts'/>
import Immutable from require('immutable');
var map1: Immutable.Map<string, number>;
map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50

The case for Immutability

Much of what makes application development difficult is tracking mutation and maintaining state. Developing with immutable data encourages you to think differently about how data flows through your application.

Subscribing to data events throughout your application creates a huge overhead of book-keeping which can hurt performance, sometimes dramatically, and creates opportunities for areas of your application to get out of sync with each other due to easy to make programmer error. Since immutable data never changes, subscribing to changes throughout the model is a dead-end and new data can only ever be passed from above.

This model of data flow aligns well with the architecture of React and especially well with an application designed using the ideas of Flux.

When data is passed from above rather than being subscribed to, and you're only interested in doing work when something has changed, you can use equality.

Immutable collections should be treated as values rather than objects. While objects represent some thing which could change over time, a value represents the state of that thing at a particular instance of time. This principle is most important to understanding the appropriate use of immutable data. In order to treat Immutable.js collections as values, it's important to use the Immutable.is() function or .equals() method to determine value equality instead of the === operator which determines object reference identity.

const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = Map({ a: 1, b: 2, c: 3 });
map1.equals(map2); // true
map1 === map2; // false

Note: As a performance optimization Immutable.js attempts to return the existing collection when an operation would result in an identical collection, allowing for using === reference equality to determine if something definitely has not changed. This can be extremely useful when used within a memoization function which would prefer to re-run the function if a deeper equality check could potentially be more costly. The === equality check is also used internally by Immutable.is and .equals() as a performance optimization.

const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 2); // Set to same value
map1 === map2; // true

If an object is immutable, it can be "copied" simply by making another reference to it instead of copying the entire object. Because a reference is much smaller than the object itself, this results in memory savings and a potential boost in execution speed for programs which rely on copies (such as an undo-stack).

const { Map } = require('immutable');
const map = Map({ a: 1, b: 2, c: 3 });
const mapCopy = map; // Look, "copies" are free!

JavaScript-first API

While Immutable.js is inspired by Clojure, Scala, Haskell and other functional programming environments, it's designed to bring these powerful concepts to JavaScript, and therefore has an Object-Oriented API that closely mirrors that of ES2015 Array, Map, and Set.

The difference for the immutable collections is that methods which would mutate the collection, like push, set, unshift or splice, instead return a new immutable collection. Methods which return new arrays, like slice or concat, instead return new immutable collections.

const { List } = require('immutable');
const list1 = List([ 1, 2 ]);
const list2 = list1.push(3, 4, 5);
const list3 = list2.unshift(0);
const list4 = list1.concat(list2, list3);
assert.equal(list1.size, 2);
assert.equal(list2.size, 5);
assert.equal(list3.size, 6);
assert.equal(list4.size, 13);
assert.equal(list4.get(0), 1);

Almost all of the methods on Array will be found in similar form on Immutable.List, those of Map found on Immutable.Map, and those of Set found on Immutable.Set, including collection operations like forEach() and map().

const { Map } = require('immutable');
const alpha = Map({ a: 1, b: 2, c: 3, d: 4 });
alpha.map((v, k) => k.toUpperCase()).join();
// 'A,B,C,D'

Convert from raw JavaScript objects and arrays.

Designed to inter-operate with your existing JavaScript, Immutable.js accepts plain JavaScript Arrays and Objects anywhere a method expects a Collection.

const { Map, List } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
const map2 = Map({ c: 10, a: 20, t: 30 });
const obj = { d: 100, o: 200, g: 300 };
const map3 = map1.merge(map2, obj);
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);
const array = [ 7, 8, 9 ];
const list3 = list1.concat(list2, array);
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

This is possible because Immutable.js can treat any JavaScript Array or Object as a Collection. You can take advantage of this in order to get sophisticated collection methods on JavaScript Objects, which otherwise have a very sparse native API. Because Seq evaluates lazily and does not cache intermediate results, these operations can be extremely efficient.

const { Seq } = require('immutable');
const myObject = { a: 1, b: 2, c: 3 };
Seq(myObject).map(x => x * x).toObject();
// { a: 1, b: 4, c: 9 }

Keep in mind, when using JS objects to construct Immutable Maps, that JavaScript Object properties are always strings, even if written in a quote-less shorthand, while Immutable Maps accept keys of any type.

const { fromJS } = require('immutable');

const obj = { 1: "one" };
console.log(Object.keys(obj)); // [ "1" ]
console.log(obj["1"], obj[1]); // "one", "one"

const map = fromJS(obj);
console.log(map.get("1"), map.get(1)); // "one", undefined

Property access for JavaScript Objects first converts the key to a string, but since Immutable Map keys can be of any type the argument to get() is not altered.

Converts back to raw JavaScript objects.

All Immutable.js Collections can be converted to plain JavaScript Arrays and Objects shallowly with toArray() and toObject() or deeply with toJS(). All Immutable Collections also implement toJSON() allowing them to be passed to JSON.stringify directly. They also respect the custom toJSON() methods of nested objects.

const { Map, List } = require('immutable');
const deep = Map({ a: 1, b: 2, c: List([ 3, 4, 5 ]) });
console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ]
console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] }
JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}'

Embraces ES2015

Immutable.js supports all JavaScript environments, including legacy browsers (even IE8). However it also takes advantage of features added to JavaScript in ES2015, the latest standard version of JavaScript, including Iterators, Arrow Functions, Classes, and Modules. It's inspired by the native Map and Set collections added to ES2015.

All examples in the Documentation are presented in ES2015. To run in all browsers, they need to be translated to ES5.

// ES2015
const mapped = foo.map(x => x * x);
// ES5
var mapped = foo.map(function (x) { return x * x; });

All Immutable.js collections are Iterable, which allows them to be used anywhere an Iterable is expected, such as when spreading into an Array.

const { List } = require('immutable');
const aList = List([ 1, 2, 3 ]);
const anArray = [ 0, ...aList, 4, 5 ]; // [ 0, 1, 2, 3, 4, 5 ]

Note: A Collection is always iterated in the same order, however that order may not always be well defined, as is the case for the Map and Set.

Nested Structures

The collections in Immutable.js are intended to be nested, allowing for deep trees of data, similar to JSON.

const { fromJS } = require('immutable');
const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }

A few power-tools allow for reading and operating on nested data. The most useful are mergeDeep, getIn, setIn, and updateIn, found on List, Map and OrderedMap.

const { fromJS } = require('immutable');
const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } });

const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }

console.log(nested2.getIn([ 'a', 'b', 'd' ])); // 6

const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1);
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }

const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6));
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }

Equality treats Collections as Values

Immutable.js collections are treated as pure data values. Two immutable collections are considered value equal (via .equals() or is()) if they represent the same collection of values. This differs from JavaScript's typical reference equal (via === or ==) for Objects and Arrays which only determines if two variables represent references to the same object instance.

Consider the example below where two identical Map instances are not reference equal but are value equal.

// First consider:
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { a: 1, b: 2, c: 3 };
obj1 !== obj2; // two different instances are always not equal with ===

const { Map, is } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = Map({ a: 1, b: 2, c: 3 });
map1 !== map2; // two different instances are not reference-equal
map1.equals(map2); // but are value-equal if they have the same values
is(map1, map2); // alternatively can use the is() function

Value equality allows Immutable.js collections to be used as keys in Maps or values in Sets, and retrieved with different but equivalent collections:

const { Map, Set } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = Map({ a: 1, b: 2, c: 3 });
const set = Set().add(map1);
set.has(map2); // true because these are value-equal

Note: is() uses the same measure of equality as Object.is for scalar strings and numbers, but uses value equality for Immutable collections, determining if both are immutable and all keys and values are equal using the same measure of equality.

Performance tradeoffs

While value equality is useful in many circumstances, it has different performance characteristics than reference equality. Understanding these tradeoffs may help you decide which to use in each case, especially when used to memoize some operation.

When comparing two collections, value equality may require considering every item in each collection, on an O(N) time complexity. For large collections of values, this could become a costly operation. Though if the two are not equal and hardly similar, the inequality is determined very quickly. In contrast, when comparing two collections with reference equality, only the initial references to memory need to be compared which is not based on the size of the collections, which has an O(1) time complexity. Checking reference equality is always very fast, however just because two collections are not reference-equal does not rule out the possibility that they may be value-equal.

Return self on no-op optimization

When possible, Immutable.js avoids creating new objects for updates where no change in value occurred, to allow for efficient reference equality checking to quickly determine if no change occurred.

const { Map } = require('immutable');
const originalMap = Map({ a: 1, b: 2, c: 3 });
const updatedMap = originalMap.set('b', 2);
updatedMap === originalMap; // No-op .set() returned the original reference.

However updates which do result in a change will return a new reference. Each of these operations occur independently, so two similar updates will not return the same reference:

const { Map } = require('immutable');
const originalMap = Map({ a: 1, b: 2, c: 3 });
const updatedMap = originalMap.set('b', 1000);
// New instance, leaving the original immutable.
updatedMap !== originalMap;
const anotherUpdatedMap = originalMap.set('b', 1000);
// Despite both the results of the same operation, each created a new reference.
anotherUpdatedMap !== updatedMap;
// However the two are value equal.
anotherUpdatedMap.equals(updatedMap);

Batching Mutations

If a tree falls in the woods, does it make a sound?

If a pure function mutates some local data in order to produce an immutable return value, is that ok?

— Rich Hickey, Clojure

Applying a mutation to create a new immutable object results in some overhead, which can add up to a minor performance penalty. If you need to apply a series of mutations locally before returning, Immutable.js gives you the ability to create a temporary mutable (transient) copy of a collection and apply a batch of mutations in a performant manner by using withMutations. In fact, this is exactly how Immutable.js applies complex mutations itself.

As an example, building list2 results in the creation of 1, not 3, new immutable Lists.

const { List } = require('immutable');
const list1 = List([ 1, 2, 3 ]);
const list2 = list1.withMutations(function (list) {
  list.push(4).push(5).push(6);
});
assert.equal(list1.size, 3);
assert.equal(list2.size, 6);

Note: Immutable.js also provides asMutable and asImmutable, but only encourages their use when withMutations will not suffice. Use caution to not return a mutable copy, which could result in undesired behavior.

Important!: Only a select few methods can be used in withMutations including set, push and pop. These methods can be applied directly against a persistent data-structure where other methods like map, filter, sort, and splice will always return new immutable data-structures and never mutate a mutable collection.

Lazy Seq

Seq describes a lazy operation, allowing them to efficiently chain use of all the higher-order collection methods (such as map and filter) by not creating intermediate collections.

Seq is immutable — Once a Seq is created, it cannot be changed, appended to, rearranged or otherwise modified. Instead, any mutative method called on a Seq will return a new Seq.

Seq is lazySeq does as little work as necessary to respond to any method call. Values are often created during iteration, including implicit iteration when reducing or converting to a concrete data structure such as a List or JavaScript Array.

For example, the following performs no work, because the resulting Seq's values are never iterated:

const { Seq } = require('immutable');
const oddSquares = Seq([ 1, 2, 3, 4, 5, 6, 7, 8 ])
  .filter(x => x % 2 !== 0)
  .map(x => x * x);

Once the Seq is used, it performs only the work necessary. In this example, no intermediate arrays are ever created, filter is called three times, and map is only called once:

oddSquares.get(1); // 9

Any collection can be converted to a lazy Seq with Seq().

const { Map, Seq } = require('immutable');
const map = Map({ a: 1, b: 2, c: 3 });
const lazySeq = Seq(map);

Seq allows for the efficient chaining of operations, allowing for the expression of logic that can otherwise be very tedious:

lazySeq
  .flip()
  .map(key => key.toUpperCase())
  .flip();
// Seq { A: 1, B: 2, C: 3 }

As well as expressing logic that would otherwise seem memory or time limited, for example Range is a special kind of Lazy sequence.

const { Range } = require('immutable');
Range(1, Infinity)
  .skip(1000)
  .map(n => -n)
  .filter(n => n % 2 === 0)
  .take(2)
  .reduce((r, n) => r * n, 1);
// 1006008

Documentation

Read the docs and eat your vegetables.

Docs are automatically generated from Immutable.d.ts. Please contribute!

Also, don't miss the Wiki which contains articles on specific topics. Can't find something? Open an issue.

Testing

If you are using the Chai Assertion Library, Chai Immutable provides a set of assertions to use against Immutable.js collections.

Contribution

Use Github issues for requests.

We actively welcome pull requests, learn how to contribute.

Changelog

Changes are tracked as Github releases.

Thanks

Phil Bagwell, for his inspiration and research in persistent data structures.

Hugh Jackson, for providing the npm package name. If you're looking for his unsupported package, see this repository.

License

Immutable.js is MIT-licensed.

Comments
  • Immutable.js is essentially unmaintained

    Immutable.js is essentially unmaintained

    I don't know what else to say. There's a lot of people here that want to help, but not much for them to do. How can we possibly guide any important new work when the community here is sitting around on a boat with no captain?

    opened by conartist6 72
  • The road to 4.0

    The road to 4.0

    So, not much has been happening since October, yet a lot of breaking changes have gone into the 4.x branch, some of these with respect to improved Records, like better typing and performance.

    I get that people are crazy busy but I really think we should try and get a 4.0 release done. How can we help?

    opened by leidegre 38
  • Extending/creating custom Immutable types

    Extending/creating custom Immutable types

    I figured a separate ticket would be a better place to discuss what an API for this feature might look like, since the potential implementation approach depends on this heavily. So here are some things I've been thinking about. While the syntax:

    class User extends Immutable.Map {
    }
    

    is kind of neat/simple and initially looks idiomatic ES6, it comes with a lot of baggage. First, it's always necessary to define a custom constructor to pass along the return value from the super call as this isn't done implicitly in js classes.

    class User extends Immutable.Map {
       constructor(val) {
          return super(val)
       }
    }
    

    Further, as the constructor doesn't really act like a normal constructor there end up being a lot of additional checks necessary to ensure that another Map passed into the custom type is coerced correctly.

    So I'm wondering whether there should be something more like:

    var User = Immutable.make(Immutable.Map, {
    
       fullName() {
         return this.get('firstName') + ' ' + this.get('lastName')
       }
    
    })
    

    would be better suited. It would allow for having a dedicated constructor type for a custom immutable type. It might still come with a perf-hit but it would be better isolated from the core implementation.

    Also, it might be worth examining at what the equivalent would have looked like in mori when implemented with cljs protocols.

    needs-decision 
    opened by tgriesser 36
  • Using Immutable.js’s Maps with TypeScript

    Using Immutable.js’s Maps with TypeScript

    I'm using immutable.js with TypeScript. I want a typed immutable object, e.g. an object called Person with an interface of: (name: string, age: number).

    Ideally I could construct a Person and it will be an instance of Immutable.Map:

    interface Person {
        name: string;
        age: number
    }
    
    var person = Person({ name: 'bob', age: 5 })
    person.name // => 'bob'
    var newPerson = person.set('name', 'harry');
    person.name // => 'bob'
    newPerson.name // => 'harry'
    

    Is this possible? Sorry if my terminology is not entirely clear!

    Thanks :smile:

    opened by OliverJAsh 35
  • Collection records

    Collection records

    I've being using Records for modelling application state and soon enough run into a case where I'd like to specify a record field that must be a collection of other Records. Something along these lines:

    const Suggestion = Record({ url: '', title: '' })
    
    const Completer = Record({
      selected: -1
      entries: List()
    })
    

    Here I'm unable to specify that Completer entries should be a Suggestion records. I would love if there was a way to declare that somewhat along these lines:

    const Suggestion = Record({ url: '', title: '' })
    
    const Completer = Record({
      selected: -1
      entries: Suggestion.List()
    })
    
    opened by Gozala 31
  • .fromJS doesn't preserve key types

    .fromJS doesn't preserve key types

    I would expect .fromJS to preserve key types, at lease for integer. Here is my test case :

    var obj = {42: "test"};
    var test = Immutable.fromJS(obj);
    
    obj.get(42); // undefined
    obj.get("42"); // "test"
    

    I might be missing something but I find it odd having to .toString() every time I .get a value.

    opened by chollier 31
  • Proposed type tweak to improve use of Record instance in TypeScript code

    Proposed type tweak to improve use of Record instance in TypeScript code

    When using records in TypeScript, it would be nice to define an interface declaring the properties. We can then access those properties, instead of going through the get method. This cleans up code and catches typos at compile time.

    interface Customer extends Map<string, any> {
      id: string;
      name: string;
    }
    
    var CustomerRecord = Immutable.Record<Customer>({ id: "", name: "" });
    
    var customer1 = new CustomerRecord({ id: "1", name: "John" });
    
    alert(customer1.id);
    customer1 = customer1.set("name", "Jon"); // Can still use as a Map
    alert(customer1.wrong); // Compile-time error here
    

    To achieve this, the Record function and interface declaration need to be made generic:

    export module Record {
      export interface Class<T extends Map<string, any>> {
        new (): T;
        new (values: { [key: string]: any }): T;
        new (values: Iterable<string, any>): T; // deprecated
      }
    }
    
    export function Record<T extends Map<string, any>>(
      defaultValues: { [key: string]: any }, name?: string
      ): Record.Class<T>;
    

    Thoughts?

    opened by andrewdavey 28
  • Most efficient way of building an indexed collection

    Most efficient way of building an indexed collection

    Hello and thank your for the work here. It works like a charm with React and Flux :)

    While the documentation is complete, it kinda lacks real life examples, and since I'm new to the immutable world, I have a hard time figuring out which structure I should pick in which case.

    I'm not sure it's a good thing I open a new issue each time I struggle with something (that is going to happen) so maybe I could ask them all here and then bundle your answers in a PR so it can help other newbies.

    I think my main use case (and many real life use cases) is: I get JSON from the server, it looks like:

    
    [
      {
        "id": "aze12",
        "someField": "someValue",
        ....
      },
      {
        "id": "67azea",
        "someField": "someValue",
        ....
      }
    ]
    

    I think the natural way of storing with Immutable is using OrderedMap. But what is the best way of building the map with "id" or "someField" as the index? Currently I create an empty OrderedMap, then iterate over my parsed data, and set them one by one within a withMutations. It doesn't feel intuitive, what do you think?

    Thank you in advance.

    opened by jsilvestre 28
  • Simplify Records

    Simplify Records

    Hi Lee (& contributors), as I wrote on Hacker News, I'd like to discuss some ideas about Records with you. I'm looking for your opinion most of all, at this point. If there is consensus, I'd be happy to help implementing things as well.

    I use Records a lot in my codebases - usually I have Map<string, SomeRecordClass>, possibly nested in another map or two, all over the place.

    I like the concept of generating a Record class at runtime. It doesn't mesh well with TypeScript, but it's very powerful and really leverages some of the things JavaScript can do better than many other languages.

    What I'm not so sure about, is the very large set of methods a Record has. I don't often iterate over all the keys in a Record. I don't usually want to build a map of all fields in a record except those that are more than 5. Maybe, somehow, it's not very useful that Record derives from Map. I'm not even sure it needs to implement Iterable.

    As long as you can convert it into something that does.

    So, how about this:

    • Record does not implement Map or anything like that
    • Record has only two methods, set and toMap.
    • The rest of a Record's namespace is nicely saved for fields. It means you can easily access fields called anything other than 'set' and 'toMap'. You'd need to do record.toMap().get('set') if your Record has a field called 'set'. Feels controversial, but really in practice this seems like an edge case.
    • Note that you don't really need update: You can just do var newRecord = oldRecord.set('someSet', oldRecord.someSet.add(5)); which is hardly more verbose, and even shorter when you don't have TypeScript / ES6 lambda syntax.

    This approach has a number of advantages. First of all, it becomes feasible to simply implement it with a vanilla JS object and Object.freeze. I'm not sure what the performance characteristics are, but I suspect that the structures underlying Map (and thus, the current Record) aren't that much more efficient than a simple shallow clone for very small amounts of fields (like is typical for records). set would just shallow-clone the object, overwrite one value (or more, maybe), then freeze the new object.

    That, in turn has a number of tangible advantages:

    • First, shorthand field access (record.fieldName) works on ES3 too (currently it is implemented with defineProperty so only ES5 browsers and up will manage)
    • Second, I suspect that there's more chances for leveraging TypeScript - Immutable.Record could simply be a base class (with set and toMap implementations) that people can derive their own classes from. I haven't completely worked this out yet, but I feel like there's ways here to at least make it somewhat better from the TypeScript perspective.

    Finally, somewhat offtopic, but why did you choose obj.set('field', value) over obj.set({field: value})?

    I know that all this totally breaks backward compatibility. At this stage I'm more interested in discussing the concept, and then if more people think it's a good idea, we can see if/how to implement it.

    opened by eteeselink 26
  • Map.get fails intermittently on iOS

    Map.get fails intermittently on iOS

    I am getting a very weird error when running in iOS (only on actual hardware, not the simulator). You can see this example for a test case. Basically after a certain number of sets/gets the Map.get function stops working entirely, even though Map.toJS() includes the correct data.

    In Firefox, Chrome, IE, Safari on desktop, and the iOS simulator this page will display "done". On actual hardware (tested on iPhone and iPad Mini running iOS 7.1.2) it will display:

    failed
    at 25
    'undefined' is not an object (evaluating 'doc.get('state').set')
    done
    

    This means that it failed on the 25th iteration, while succeeding on all previous iterations. It also seems that once it does this, Map.get will be broken forever after, until a page reload.

    opened by conradz 24
  • hashing breaks for custom objects with

    hashing breaks for custom objects with "Invalid value used as weak map key"

    I think the latest changes to Hash.js introduce a weird bug when hashing custom objects, more specifically, a class with valueOf() overridden. The error being thrown is Uncaught TypeError: Invalid value used as weak map key.

    It's strange because it doesn't happen until a certain point, a very specific point. It happens when invoking .set() on a Map on the 9th attempt. For the first 8 attempts, all is good. On the 9th attempt, error.

    To reproduce, I ran this bit of code in the console at https://facebook.github.io/immutable-js.

    class Example {
      constructor(id, key) { this.id = id; this.key = key; }
      valueOf() { return `${this.id}.${this.key}`; } 
      toString() { return `${this.id}.${this.key}`; }
    }
    
    const m = Immutable.Map().asMutable();
    m.set(new Example('test', (new Date()).toISOString()), Math.random()); // 1, ok
    ...
    m.set(new Example('test', (new Date()).toISOString()), Math.random()); // 8, ok
    m.set(new Example('test', (new Date()).toISOString()), Math.random()); // 9, ERROR
    

    This has worked for me for quite a while. It breaks with release v4.0.0-rc.11.

    Here's a screenshot of the console:

    screen shot 2018-11-06 at 12 17 27 pm

    bug 
    opened by UnsungHero97 22
  • Converting a Seq to a list causes RangeError (max call size exceeded)

    Converting a Seq to a list causes RangeError (max call size exceeded)

    What happened

    Converting a Seq to a list on anything remotely large (even a Seq with 1000 items seems to be enough) causes a max call size exceeded error.

    After tracing through the code a bit, it seems to be happening because the implementation of flatDeep is unnecessarily recursive (it iterates recursively in the default case).

    How to reproduce

    This codesandbox repros the issue: https://codesandbox.io/s/stoic-brook-zlzcs6?file=/src/index.js

    bug 
    opened by phou-patreon 1
  • Supporting wildcards

    Supporting wildcards

    Supporting wildcards

    It would be useful to be able to pass wildcards (*) in path for setIn removeIn, updateIn methods. A wildcard should match all elements in an array or all props in an object.

    Example

    {
        a: {
            b: 1,
            c: [
                {x: 1, y: 2}
            ]
        },
        b: {
            b: 1,
            c: [
                {x: 1, y: 2}
            ]
        }
    }
    
    deleteIn(x, ['*', 'c', 'x'])
    

    Out

    {
        a: {
            b: 1,
            c: [
                {y: 2}
            ]
        },
        b: {
            b: 1,
            c: [
                {y: 2}
            ]
        }
    }
    
    opened by SunPj 7
  • createSerializableStateInvariantMiddleware for Record in React Redux TS

    createSerializableStateInvariantMiddleware for Record in React Redux TS

    https://redux-toolkit.js.org/api/serializabilityMiddleware has example with Immutable JS Iterable. How create it for Record?

    What happened

    console error

    react_devtools_backend.js:4026 A non-serializable value was detected in the state, in the path: `<root>`. Value: Record
    

    How to reproduce

    put in react redux store Record and load page

    opened by long76 1
  • Draft empty unwrapping

    Draft empty unwrapping

    This is a partially complete work to create a new empty data structure of the same type via a well known instance method.

    Incomplete, so marked as a draft. I'm just preserving this branch remotely to ensure it doesn't get lost locally

    opened by leebyron 0
Releases(v4.2.1)
  • v4.2.1(Dec 23, 2022)

    What's Changed

    • [Typescript] rollback some of the change on toJS to avoir circular reference by @jdeniau in https://github.com/immutable-js/immutable-js/pull/1922

    Full Changelog: https://github.com/immutable-js/immutable-js/compare/v4.2.0...v4.2.1

    Source code(tar.gz)
    Source code(zip)
  • v4.2.0(Dec 22, 2022)

    • Added a partition method to all containers #1916 by johnw42
    • [TypeScript] Better type for toJS #1917 by jdeniau
      • [TS Minor Break] tests are ran with TS > 4.5 only. It was tested with TS > 2.1 previously, but we want to level up TS types with recent features. TS 4.5 has been released more than one year before this release. If it does break your implementation (it might not), you should probably consider upgrading to the latest TS version.
    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(May 23, 2022)

    Docs: https://immutable-js.com/docs/v4.1.0/ Changelog Doc: https://github.com/immutable-js/immutable-js/blob/fb4701a71ca3b138cb31b6697f047e637780867e/CHANGELOG.md#410---2022-05-23 Full Changelog: https://github.com/immutable-js/immutable-js/compare/v4.0.0...v4.1.0

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Oct 7, 2021)

    Docs: https://immutable-js.com/docs/v4.0.0/ Full Changelog: https://github.com/immutable-js/immutable-js/compare/v3.8.1...v4.0.0

    Key changes

       Diff of changed API (click to expand)
    +  Collection.[Symbol.iterator]
    +  Collection.toJSON
    +  Collection.update
    +  Collection.Indexed.[Symbol.iterator]
    +  Collection.Indexed.toJSON
    +  Collection.Indexed.update
    +  Collection.Indexed.zipAll
    +  Collection.Keyed.[Symbol.iterator]
    +  Collection.Keyed.toJSON
    +  Collection.Keyed.update
    +  Collection.Set.[Symbol.iterator]
    +  Collection.Set.toJSON
    +  Collection.Set.update
    -  Collection.size
    -  Collection.Indexed.size
    -  Collection.Keyed.size
    -  Collection.Set.size
    
    +  List.[Symbol.iterator]
    +  List.toJSON
    +  List.wasAltered
    +  List.zipAll
    -  List.mergeDeep
    -  List.mergeDeepWith
    -  List.mergeWith
    
    +  Map.[Symbol.iterator]
    +  Map.deleteAll
    +  Map.toJSON
    +  Map.wasAltered
    
    +  OrderedMap.[Symbol.iterator]
    +  OrderedMap.deleteAll
    +  OrderedMap.toJSON
    +  OrderedMap.wasAltered
    +  OrderedSet.[Symbol.iterator]
    +  OrderedSet.toJSON
    +  OrderedSet.update
    +  OrderedSet.wasAltered
    +  OrderedSet.zip
    +  OrderedSet.zipAll
    +  OrderedSet.zipWith
    
    +  Record.[Symbol.iterator]
    +  Record.asImmutable
    +  Record.asMutable
    +  Record.clear
    +  Record.delete
    +  Record.deleteIn
    +  Record.merge
    +  Record.mergeDeep
    +  Record.mergeDeepIn
    +  Record.mergeDeepWith
    +  Record.mergeIn
    +  Record.mergeWith
    +  Record.set
    +  Record.setIn
    +  Record.toJSON
    +  Record.update
    +  Record.updateIn
    +  Record.wasAltered
    +  Record.withMutations
    +  Record.Factory.displayName
    -  Record.butLast
    -  Record.concat
    -  Record.count
    -  Record.countBy
    -  Record.entries
    -  Record.entrySeq
    -  Record.every
    -  Record.filter
    -  Record.filterNot
    -  Record.find
    -  Record.findEntry
    -  Record.findKey
    -  Record.findLast
    -  Record.findLastEntry
    -  Record.findLastKey
    -  Record.first
    -  Record.flatMap
    -  Record.flatten
    -  Record.flip
    -  Record.forEach
    -  Record.groupBy
    -  Record.includes
    -  Record.isEmpty
    -  Record.isSubset
    -  Record.isSuperset
    -  Record.join
    -  Record.keyOf
    -  Record.keySeq
    -  Record.keys
    -  Record.last
    -  Record.lastKeyOf
    -  Record.map
    -  Record.mapEntries
    -  Record.mapKeys
    -  Record.max
    -  Record.maxBy
    -  Record.min
    -  Record.minBy
    -  Record.reduce
    -  Record.reduceRight
    -  Record.rest
    -  Record.reverse
    -  Record.skip
    -  Record.skipLast
    -  Record.skipUntil
    -  Record.skipWhile
    -  Record.slice
    -  Record.some
    -  Record.sort
    -  Record.sortBy
    -  Record.take
    -  Record.takeLast
    -  Record.takeUntil
    -  Record.takeWhile
    -  Record.toArray
    -  Record.toIndexedSeq
    -  Record.toKeyedSeq
    -  Record.toList
    -  Record.toMap
    -  Record.toOrderedMap
    -  Record.toOrderedSet
    -  Record.toSet
    -  Record.toSetSeq
    -  Record.toStack
    -  Record.valueSeq
    -  Record.values
    
    +  Seq.[Symbol.iterator]
    +  Seq.toJSON
    +  Seq.update
    +  Seq.Indexed.[Symbol.iterator]
    +  Seq.Indexed.toJSON
    +  Seq.Indexed.update
    +  Seq.Indexed.zipAll
    +  Seq.Keyed.[Symbol.iterator]
    +  Seq.Keyed.toJSON
    +  Seq.Keyed.update
    +  Seq.Set.[Symbol.iterator]
    +  Seq.Set.toJSON
    +  Seq.Set.update
    
    +  Set.[Symbol.iterator]
    +  Set.toJSON
    +  Set.update
    +  Set.wasAltered
    
    +  Stack.[Symbol.iterator]
    +  Stack.toJSON
    +  Stack.update
    +  Stack.wasAltered
    +  Stack.zipAll
    
    +  ValueObject.equals
    +  ValueObject.hashCode
    
    -  Iterable.*
    -  Iterable.Indexed.*
    -  Iterable.Keyed.*
    -  Iterable.Set.*
    

    Note for users of v4.0.0-rc.12

    There were mostly bugfixes and improvements since RC 12. Upgrading should be painless for most users. However, there is one breaking change: The behavior of merge and mergeDeep has changed. See below for details.

    BREAKING

    merge()

    • No longer use value-equality within merge() (#1391)

      This rectifies an inconsistent behavior between x.merge(y) and x.mergeDeep(y) where merge would use === on leaf values to determine return-self optimizations, while mergeDeep would use is(). This improves consistency across the library and avoids a possible performance pitfall.

    • No longer deeply coerce argument to merge() (#1339)

      Previously, the argument provided to merge() was deeply converted to Immutable collections via fromJS(). This was the only function in the library which calls fromJS() indirectly, and it was surprising and made it difficult to understand what the result of merge() would be. Now, the value provided to merge() is only shallowly converted to an Immutable collection, similar to related methods in the library. This may change the behavior of your calls to merge().

    mergeDeep()

    • Replace incompatible collections when merging nested data (#1840)

      It will no longer merge lists of tuples into maps. For more information see #1840 and the updated mergeDeep() documentation.

    • Concat Lists when merging deeply (#1344)

      Previously, calling map.mergeDeep() with a value containing a List would replace the values in the original List. This has always been confusing, and does not properly treat List as a monoid. Now, List.merge is simply an alias for List.concat, and map.mergeDeep() will concatenate deeply-found lists instead of replacing them.

    Seq

    • Remove IteratorSequence. Do not attempt to detect iterators in Seq(). (#1589)

      Iterables can still be provided to Seq(), and most Iterators are also Iterables, so this change should not affect the vast majority of uses. For more information, see PR #1589

    • Remove Seq.of() (#1311, #1310)

      This method has been removed since it cannot be correctly typed. It's recommended to convert Seq.of(1, 2, 3) to Seq([1, 2, 3]).

    isImmutable()

    • isImmutable() now returns true for collections currently within a withMutations() call. (#1374)

      Previously, isImmutable() did double-duty of both determining if a value was a Collection or Record from this library as well as if it was outside a withMutations() call. This latter case caused confusion and was rarely used.

    toArray()

    • KeyedCollection.toArray() returns array of tuples. (#1340)

      Previously, calling toArray() on a keyed collection (incl Map and OrderedMap) would discard keys and return an Array of values. This has always been confusing, and differs from Array.from(). Now, calling toArray() on a keyed collection will return an Array of [key, value] tuples, matching the behavior of Array.from().

    concat()

    • list.concat() now has a slightly more efficient implementation and map.concat() is an alias for map.merge(). (#1373)

      In rare cases, this may affect use of map.concat() which expected slightly different behavior from map.merge().

    Collection, formerly Iterable

    • The Iterable class has been renamed to Collection, and isIterable() has been renamed to isCollection(). Aliases with the existing names exist to make transitioning code easier.

    Record

    • Record is no longer an Immutable Collection type.
      • Now isCollection(myRecord) returns false instead of true.
      • The sequence API (such as map, filter, forEach) no longer exist on Records.
      • delete() and clear() no longer exist on Records.

    Other breaking changes

    • Potentially Breaking: Improve hash speed and avoid collision for common values (#1629)

      Causes some hash values to change, which could impact the order of iteration of values in some Maps (which are already advertised as unordered, but highlighting just to be safe)

    • Node buffers no longer considered value-equal (#1437)

    • Plain Objects and Arrays are no longer considered opaque values (#1369)

      This changes the behavior of a few common methods with respect to plain Objects and Arrays where these were previously considered opaque to merge() and setIn(), they now are treated as collections and can be merged into and updated (persistently). This offers an exciting alternative to small Lists and Records.

    • The "predicate" functions, isCollection, isKeyed, isIndexed, isAssociative have been moved from Iterable. to the top level exports.

    • The toJSON() method performs a shallow conversion (previously it was an alias for toJS(), which remains a deep conversion).

    • Some minor implementation details have changed, which may require updates to libraries which deeply integrate with Immutable.js's private APIs.

    • The Cursor API is officially deprecated. Use immutable-cursor instead.

    • Potentially Breaking: [TypeScript] Remove Iterable<T> as tuple from Map constructor types (#1626)

      Typescript allowed constructing a Map with a list of List instances, assuming each was a key, value pair. While this runtime behavior still works, this type led to more issues than it solved, so it has been removed. (Note, this may break previous v4 rcs, but is not a change against v3)

    Full Changelog: https://github.com/immutable-js/immutable-js/compare/v3.8.1...v4.0.0

    New

    • Update TypeScript and Flow definitions:
      • The Flowtype and TypeScript type definitions have been completely rewritten with much higher quality and accuracy, taking advantage of the latest features from both tools.
      • Simplified TypeScript definition files to support all UMD use cases (#1854)
      • Support Typescript 3 (#1593)
      • Support Typescript strictNullChecks (#1168)
      • Flow types to be compatible with the latest version 0.160.0
      • Enable flow strict (#1580)
    • Add "sideEffects: false" to package.json (#1661)

    • Use ES standard for iterator method reuse (#1867)

    • Generalize fromJS() and Seq() to support Sets (#1865)

    • Top level predicate functions (#1600)

      New functions are exported from the immutable module: isSeq(), isList(), isMap(), isOrderedMap(), isStack(), isSet(), isOrderedSet(), and isRecord().

    • Improve performance of toJS (#1581)

      Cursory test is >10% faster than both v3.8.2 and v4.0.0-rc.7, and corrects the regression since v4.0.0-rc.9.

    • Added optional notSetValue in first() and last() (#1556)

    • Make isArrayLike check more precise to avoid false positives (#1520)

    • map() for List, Map, and Set returns itself for no-ops (#1455) (5726bd1)

    • Hash functions as objects, allowing functions as values in collections (#1485)

    • Functional API for get(), set(), and more which support both Immutable.js collections and plain Objects and Arrays (#1369)

    • Relicensed as MIT (#1320)

    • Support for Transducers! (ee9c68f1)

    • Add new method, zipAll() (#1195)

    • Bundle and distribute an "es module" so Webpack and Rollup can use tree-shaking for smaller builds (#1204)

    • Warn instead of throw when getIn() has a bad path (668f2236)

    • A new predicate function isValueObject() helps to detect objects which implement equals() and hashCode(), and type definitions now define the interface ValueObject which you can implement in your own code to create objects which behave as values and can be keys in Maps or entries in Sets.

    • Using fromJS() with a "reviver" function now provides access to the key path to each translated value. (#1118)

    Fixed

    • Fix issue with IE11 and missing Symbol.iterator (#1850)

    • Fix ordered set with map (#1663)

    • Do not modify iter during List.map and Map.map (#1649)

    • Fix ordered map delete all (#1777)

    • Hash symbols as objects (#1753)

    • Fix returning a Record in merge() when Record is empty (#1785)

    • Fix for RC~12: Records from different factories aren't equal (#1734)

    • "too much recursion" error when creating a Record type from an instance of another Record (#1690)

    • Fix glob for npm format script on Windows (#18)

    • Remove deprecated cursor API (#13)

    • Add missing es exports (#1740)

    • Support nulls in genTypeDefData.js (#185)

    • Support isPlainObj in IE11 and other esoteric parameters f3a6d5ce

    • Set.map produces valid underlying map (#1606)

    • Support isPlainObj with constructor key (#1627)

    • groupBy no longer returns a mutable Map instance (#1602)

    • Fix issue where refs can recursively collide, corrupting .size (#1598)

    • Throw error in mergeWith() method if missing the required merger function (#1543)

    • Update isPlainObj() to workaround Safari bug and allow cross-realm values (#1557)

    • Fix missing "& T" to some methods in RecordInstance (#1464)

    • Make notSetValue optional for typed Records (#1461) (a1029bb)

    • Export type of RecordInstance (#1434)

    • Fix Record size check in merge() (#1521)

    • Fix Map#concat being not defined (#1402)

    • getIn() no longer throws when encountering a missing path (#1361)
    • Do not throw when printing value that cannot be coerced to primitive (#1334)
    • Do not throw from hasIn (#1319)

    • Long hash codes no longer cause an infinite loop (#1175)

    • slice() which should return an empty set could return a full set or vice versa (#1245, #1287)

    • Ensure empty slices do not throw when iterated (#1220)

    • Error during equals check on Record with undefined or null (#1208)

    • Fix size of count() after filtering or flattening (#1171)

    Changes since v4.0.0-rc.15

    • Ensure latest version docs are built by @leebyron in https://github.com/immutable-js/immutable-js/pull/1877
    • Add correct types for empty Seq and Collection by @leebyron in https://github.com/immutable-js/immutable-js/pull/1878
    • keep sidebar fixed + merge top and bottom sidebar by @jdeniau in https://github.com/immutable-js/immutable-js/pull/1868
    • Changelog 4.0.0 by @bdurrer in https://github.com/immutable-js/immutable-js/pull/1880

    New Contributors

    • @bdurrer made their first contribution in https://github.com/immutable-js/immutable-js/pull/1880

    Full Changelog: https://github.com/immutable-js/immutable-js/compare/v4.0.0-rc.15...v4.0.0

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.15(Sep 16, 2021)

    This is the last planned RC release before releasing a stable 4.0!! 🎉 🎉 🎉

    BREAKING:

    • Replace incompatible collections when merging nested data with mergeDeep() (#1840)
      • This means that mergeDeep() will no longer merge lists of tuples into maps. For more information see https://github.com/immutable-js/immutable-js/pull/1840 and the updated mergeDeep() documentation.

    New:

    • Add "sideEffects: false" to package.json (#1661)
    • Update Flow types to be compatible with the latest version (#1863)
    • Use ES standard for iterator method reuse (#1867)
    • Generalize fromJS() and Seq() to support Sets (#1865)

    Fixes:

    • Fix some TS type defs (#1847)
      • Adds ArrayLike<T> as option to type factory functions and fromJS now returns Collection<unknown> instead of just unknown.
    • Fix issue with IE11 and missing Symbol.iterator (#1850)
    • Simplify typescript definition files to support all UMD use cases (#1854)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.14(Jul 7, 2021)

  • v4.0.0-rc.13(Jul 7, 2021)

    Hi there !

    It's been a while since 4.0.0-rc.12 ! If you want to know why, there is a warm message from @leebyron, who developed and maintained immutable during all these years.

    In the meantime, @Methuselah96 and @conartist6 did fork immutable-js on another repository, opened a slack, and helped with some great talent (@bdurrer, @mcclure, @hahnlee, @mishawakerman), they tried to fixed issues in the 4.x version in order to release that 4.0.0 version !

    We are not there right now, but we are getting closer. There are still some PRs and issues until then, but they might be minor.

    Once again, thanks a LOT to @leebyron for all the hard work that he put on immutable during all this years.

    This version is not published to npmjs, you can try the 4.0.0-rc.14 instead.

    This RC does not contain any BC break since 4.0.0-rc.12.

    Fixes that should be resolved in this version :

    • Fix ordered set with map (#1663)
    • fix: do not modify iter during List.map and Map.map (#1649)
    • Fix ordered map delete all (#1777)
    • Hash symbols as objects (#1753)
    • Fix returning a Record in merge() when Record is empty (#1785)
    • Similar factories should be equals (#1734)
    • "too much recursion" error when creating a Record type from an instance of another Record (#1690)
    • Record clear does work (#1565)
    • Fix glob for npm format script on Windows https://github.com/immutable-js-oss/immutable-js/pull/18
    • Remove deprecated cursor API https://github.com/immutable-js-oss/immutable-js/issues/13
    • Add missing es exports (#1740)
    • Support nulls in genTypeDefData.js (#185)
    • Support isPlainObj in IE11 and other esoteric parameters https://github.com/immutable-js/immutable-js/pull/1833/commits/f3a6d5ce75bb9d60b87074240838f5429e896b60
    • Fix benchmarks https://github.com/immutable-js-oss/immutable-js/pull/21
    • ensure that subtract works correcly (#1716, #1603)
    • assert that setIn works as expected (#1428)
    • check that "delete" works as "remove" (#1474)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.12(Oct 30, 2018)

    Fixes:

    • Update to support Flow v0.85 and makes Record strict typing optional to ease migration from v3 or earlier v4 release candidates (#1636)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.11(Oct 27, 2018)

    Potentially Breaking:

    • Improve hash speed and avoid collision for common values (#1629)

      Causes some hash values to change, which could impact the order of iteration of values in some Maps (which are already advertised as unordered, but highlighting just to be safe)

    • [TypeScript] Remove Iterable<T> as tuple from Map constructor types (#1626)

      Typescript allowed constructing a Map with a list of List instances, assuming each was a key, value pair. While this runtime behavior still works, this type led to more issues than it solved so it has been removed. (Note, this may break previous v4 rcs, but is not a change against v3)

    Fixes:

    • Give Records a displayName (#1625)
    • Set.map produces valid underlying map (#1606)
    • Support isPlainObj with constructor key (#1627)

    Docs:

    • Fix missing sub-types in API docs (#1619)
    • Add docsearch (#1610)
    • Add styles to doc search (#1628)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.10(Sep 19, 2018)

    It's been a long time since the last release candidate, but quite a bit of work has happened since the last once. One step closer to a final release!

    Breaking:

    • Remove IteratorSequence. Do not attempt to detect iterators in Seq(). (#1589)

      Iterables can still be provided to Seq(), and most Iterators are also Iterables, so this change should not affect the vast majority of uses. For more information, see PR #1589

    • Node buffers no longer considered value-equal

      This was actually broken as of v4.0.0-rc.1 (2dcf3ef94db9664c99a0a48fd071b95c0008e18f) but was highlighted as a breaking change by (#1437)

    New:

    • Top level predicate functions (#1600)

      New functions are exported from the immutable module: isSeq(), isList(), isMap(), isOrderedMap(), isStack(), isSet(), isOrderedSet(), and isRecord().

    • Support Typescript 3 (#1593)
    • Support latest Flow (#1531)
    • Add RecordOf<TProps> type alias for TypeScript, matching Flow (#1578)
    • Improved Flow support for Record subclasses (still not advised) (#1414)
    • Improve performance of toJS (#1581)

      Cursory test is >10% faster than both v3.8.2 and v4.0.0-rc.7, and corrects the regression since v4.0.0-rc.9.

    • Added optional notSetValue in first() and last() (#1556)
    • Enable flow strict (#1580)
    • Make isArrayLike check more precise to avoid false positives (#1520)
    • map() for List, Map, and Set returns itself for no-ops (#1455) (5726bd1)
    • Hash functions as objects, allowing functions as values in collections (#1485)

    Fix:

    • groupBy no longer returns a mutable Map instance (#1602)
    • Fix issue where refs can recursively collide, corrupting .size (#1598)
    • Throw error in mergeWith() method if missing the required merger function (#1543)
    • Update isPlainObj() to workaround Safari bug and allow cross-realm values (#1557)
    • The mergeDeepWith merger is untypable in TS/Flow. (#1532)
    • Fix missing "& T" to some methods in RecordInstance (#1464)
    • Make notSetValue optional for typed Records (#1461) (a1029bb)
    • Export type of RecordInstance (#1434)
    • Fix Record size check in merge() (#1521)
    • Fix Map#concat being not defined (#1402)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.9(Oct 18, 2017)

    Fixes:

    • Improved typescript definitions for new functional API (#1395)
    • Improved flow types for Record setIn()/getIn() key-paths. (#1399)
    • Improved flow types for functional merge() definitions. (#1400)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.8(Oct 17, 2017)

    BREAKING:

    • list.concat() now has a slightly more efficient implementation and map.concat() is an alias for map.merge(). (#1373)

      In rare cases, this may affect use of map.concat() which expected slightly different behavior from map.merge().

    • isImmutable() now returns true for collections currently within a withMutations() call. (#1374)

      Previously, isImmutable() did double-duty of both determining if a value was a Collection or Record from this library as well as if it was outside a withMutations() call. This latter case caused confusion and was rarely used.

    • Plain Objects and Arrays are no longer considered opaque values (#1369)

      This changes the behavior of a few common methods with respect to plain Objects and Arrays where these were previously considered opaque to merge() and setIn(), they now are treated as collections and can be merged into and updated (persistently). This offers an exciting alternative to small Lists and Records.

    • No longer use value-equality within merge() (#1391)

      This rectifies an inconsistent behavior between x.merge(y) and x.mergeDeep(y) where merge would use === on leaf values to determine return-self optimizations, while mergeDeep would use is(). This improves consistency across the library and avoids a possible performance pitfall.

    New:

    • Dramatically better Flow types for getIn(), setIn(), updateIn() which understand key paths (#1366, #1377)
    • Functional API for get(), set(), and more which support both Immutable.js collections and plain Objects and Arrays (#1369)

    Fixed:

    • getIn() no longer throws when encountering a missing path (#1361)
    • Flow string enums can now be used as Map keys or Record fields (#1376)
    • Flow now allows record.get() to provide a not-set-value (#1378)
    • Fixed Flow return type for Seq.Set() (3e671a2b6dc76ab3dd141c65659bce55ffd64f44)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.7(Oct 5, 2017)

  • v4.0.0-rc.6(Oct 5, 2017)

    Fixes:

    • Flow types now understand list.filter(Boolean) will remove null values (#1352)
    • Added missing flow types for Record.hasIn and Record.getIn (#1350)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.5(Oct 5, 2017)

    BREAKING:

    • Concat Lists when merging deeply (#1344)

      Previously, calling map.mergeDeep() with a value containing a List would replace the values in the original List. This has always been confusing, and does not properly treat List as a monoid. Now, List.merge is simply an alias for List.concat, and map.mergeDeep() will concatenate lists instead of replacing them.

    • No longer deeply coerce argument to merge() (#1339)

      Previously, the argument provided to merge() was deeply converted to Immutable collections via fromJS(). This was the only function in the library which calls fromJS() indirectly directly, and it was surprising and made it difficult to understand what the result of merge() would be. Now, the value provided to merge() is only shallowly converted to an Immutable collection, similar to related methods in the library. This may change the behavior of your calls to merge().

    • KeyedCollection.toArray() returns array of tuples. (#1340)

      Previously, calling toArray() on a keyed collection (incl Map and OrderedMap) would discard keys and return an Array of values. This has always been confusing, and differs from Array.from(). Now, calling toArray() on a keyed collection will return an Array of [key, value] tuples, matching the behavior of Array.from().

    New:

    • Much better documentation for Records (http://facebook.github.io/immutable-js/docs/#/Record) (#1349)
    • Include version in build (#1345)
    • Flow types RecordOf<T> and RecordFactory<T> dramatically improve the Flow types for Records (#1343, #1330)

    Fixed:

    • zipAll type should predict undefined values (#1322)
    • Do not throw when printing value that cannot be coerced to primitive (#1334)
    • Ensure set.subtract() accepts any iterable. (#1338)
    • Fix TypeScript definitions for merge functions (#1336)
    • Ensure when OrderedSet becomes empty, that it remains OrderedSet (#1335)
    • Fix slow iterator for Set (#1333)
    • Add proper typescript type for map.flip() (#1332)
    • Set wasAltered() to false after List.asImmutable() (#1331)
    Source code(tar.gz)
    Source code(zip)
  • v3.8.2(Oct 5, 2017)

    This patch release relicenses with the MIT license, but includes no other changes. Intended for those who have not yet been able to update to the 4.x builds, but have a legal need for the change in license.

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.4(Oct 5, 2017)

    Fixes:

    • Fixed a regression from rc.3 where value hashing was not working (#1325, #1328)
    • Stop the iteration of an exhausted, unknown-sized sequence when slicing (#1324)
    • Flow type the prototype chain of "plain object" inputs (#1328)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.3(Sep 30, 2017)

    This RC is now relicensed as MIT (#1320)

    BREAKING:

    • Remove Seq.of() (#1311, #1310 )

      This method has been removed since it cannot be correctly typed. It's recommended to convert Seq.of(1, 2, 3) to Seq([1, 2, 3]).

    New:

    • Support for Transducers! (ee9c68f1d43da426498ee009ecea37aa2ef77cb8)
    • A new method, zipAll() (#1195)
    • Considerably improved Record typing (#1193, #1276)
    • Bundle and distribute an "es module" so Webpack and Rollup can use tree-shaking for smaller builds (#1204)
    • Warn instead of throw when getIn() has a bad path (668f2236642c97bd4e7d8dfbf62311f497a6ac18)
    • Improved TypeScript types for zip(). (#1258)
    • Improved TypeScript types for has(). (#1232)
    • Support typescript strictNullChecks (#1168)

    Fixed:

    • Updated Flow types to work with 0.55 and higher (#1312)
    • Updated TypeScript types to work with v2.4 and higher (#1285)
    • Do not throw from hasIn (#1319)
    • Long hash codes no longer cause an infinite loop (#1175)
    • slice() which should return an empty set could return a full set or vice versa (#1245, #1287)
    • Ensure empty slices do not throw when iterated (#1220)
    • Error during equals check on Record with undefined or null (#1208)
    • Fixes missing size property in flow types. (#1173)
    • Fix size of count() after filtering or flattening (#1171)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.2(Mar 13, 2017)

    Changes Since v4.0.0-rc.1:

    • Type definition improvements for filter(), reduce() and concat() (#1155, #1156, #1153)
    • More specific TypeScript type definitions (#1149)
    • Added back delete() and clear() to Record instances (#1157)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc.1(Mar 11, 2017)

    This is a pre-release version of Immutable.js. Please try it at your own risk and report any issues you encounter so an official release can be shipped with great confidence.

    As a pre-release, this changelog doesn't contain everything that has changed. Take a look at the commit log for a complete view, and expect a more thorough changelog for the official release.

    Breaking Changes

    • The Iterable class has been renamed to Collection, and isIterable() has been renamed to isCollection(). Aliases with the existing names exist to make transitioning code easier.

    • The "predicate" functions, isCollection, isKeyed, isIndexed, isAssociative have been moved from Iterable. to the top level exports.

    • Record is no longer an Immutable Collection type.

      • Now isCollection(myRecord) returns false instead of true.
      • The sequence API (such as map, filter, forEach) no longer exist on Records.
      • delete() and clear() no longer exist on Records.
    • The toJSON() method is now a shallow conversion (previously it was an alias for toJS(), which remains a deep conversion).

    • Some minor implementation details have changed, which may require updates to libraries which deeply integrate with Immutable.js's private APIs.

    • The Cursor API is officially deprecated. Use immutable-cursor instead.

    New Stuff!

    • A new predicate function isValueObject() helps to detect objects which implement equals() and hashCode(), and type definitions now define the interface ValueObject which you can implement in your own code to create objects which behave as values and can be keys in Maps or entries in Sets.

    • The Flowtype and TypeScript type definitions have been completely rewritten with much higher quality and accuracy, taking advantage of the latest features from both amazing tools.

    • Using fromJS() with a "reviver" function now provides access to the key path to each translated value. (#1118)

    Bug fixes

    • Numerous bug fixes have gone into this release.
    Source code(tar.gz)
    Source code(zip)
  • v3.8.1(Apr 18, 2016)

    Minor touch ups discovered after the last release, plus a few more bug fixes! Plus, you can now contribute to immutable-js using the latest version of node.

    New:

    • The methods keyOf, findKey, lastKeyOf, and findLastKey were moved from KeyedIterable to Iterable, so they may be also used on Lists and Sets. (#740)

    Fixes:

    • Some issues with the flow definitions have been polished out thanks to @marudor. (#840, #841, #845)
    • Collections which contain Symbol keys or values can now be stringified. (#620)
    • Negative indexing into the keySeq of an IndexedIterable returns correct results. (#811)
    • Can use the value Infinity as a key in a Collection without crashing. (#797)
    Source code(tar.gz)
    Source code(zip)
  • v3.8.0(Apr 16, 2016)

    Whoa, a new version of Immutable! The big news is that we now export types for both Flow and TypeScript in the npm module! Also that pesky length warning has finally been fully removed. There are also a good amount of small bug fixes and performance improvements. Finally, the API docs have been improved greatly! Check it out http://facebook.github.io/immutable-js/docs/.

    A huge huge thanks to everyone in the community for contributing these improvements. The large majority of work cited below is community contributions.

    New:

    • Now exports Flow types (#805)
    • Now exports typings for TypeScript use. (#808)
    • Cursor TypeScript definitions (#765)
    • No longer warns when accessing length property of a collection. (88f880fc02a377eb36dc1b9f3d6c86c2d1c287dd)
    • Map.of() takes key, value interleaved pairs (#727)
    • findEntry and findLastEntry now respect notSetValue argument (#822)

    Fixes:

    • Iterable::take(Infinity) takes infinitely instead of 0 (#834)
    • Proper toOrderedMap and toOrderedSet method definitions (#761)
    • Records return themselves for no-op Record#set calls for better performance (#795)
    • Range#toString propertly reports step (#759)
    • Add missing Set#contains (96b09465f95a4f9f5229b4183a06faca39235fec)
    Source code(tar.gz)
    Source code(zip)
  • 3.7.6(Dec 16, 2015)

    A few minor bug fixes:

    • Fixed issue where lastIndexOf did not always return the correct value #703
    • mergeDeep now has more opportunities to for the "return self" optimization, saving memory #690
    • The TypeScript .d.ts file now aligns with the outputted file for the variations of Immutable Iterables. #647
    • Ensure behavior for slice(0, NaN) is equivalent to that of JS Array #623
    • Ensure ES6 Symbol can be properly hashed #579

    And a new API method:

    • myList.insert() #402
    Source code(tar.gz)
    Source code(zip)
  • 3.7.5(Sep 2, 2015)

    Many stability improvements thanks to excellent community submitted fixes.

    New:

    • Cursor can now set(value) #516 to replace the value at the cursor.

    Fixes:

    • Ensure all tests pass in node v0.12
    • All operations that accept indicies now use ECMA's algorithm for converting input to integers when possible. #545 #598
    • Fix issue where slice/splice with non-number arguments could result in infinite recursion. #511
    • Clearer documentation regarding creating Map from JS Obj #589
    • Immutable now exported as a TypeScript module #567
    • Trailing commas causing issues in IE8 #510
    • Fix memory leak from setSize() and slice() #540
    • Union and Merge of Map or Set always favors the type of the left hand side #515
    Source code(tar.gz)
    Source code(zip)
  • 3.7.4(Jun 17, 2015)

    Fixes:

    • isSuperset can be called with an array of values.

    New:

    • contrib/Cursor has proper support for Record
    • tsc will pick up type definitions from node modules
    Source code(tar.gz)
    Source code(zip)
  • 3.7.3(May 20, 2015)

    Fixes:

    • Improvements to documentation around equality, hasIn and withMutations
    • Iterating over empty slice no longer throws.
    • Merge deep methods no longer throw if deep position is not mergeable.
    Source code(tar.gz)
    Source code(zip)
  • 3.7.2(Apr 10, 2015)

  • 3.7.1(Mar 29, 2015)

  • 3.7.0(Mar 27, 2015)

    New:

    • merge() family of functions now get the currently merging key as a 3rd argument, in case merge strategy should alter based on key.
    • IndexedCursor now has push(), pop(), unshift() and shift() to more closely mirror List.
    • Records initialize lazily. Creating a new Record type with Record({foo:"bar"}) involves a small bit of work. For applications with a large amount of Records, lazy initialization should help startup times.
    • Maps can now be constructed by a List of Lists instead of only a List of Arrays.
    • toString() prints Map string keys in quotes.

    Fixes:

    • is() allows usage of valueOf to return primitives without recursing or encountering a reference error.
    • merge()/union() work inside withMutations when initial collection is empty. #405
    • Producing subcursors using cursor.cursor() now returns a proper typed cursor. #381
    • When a Record is passed to the same Record creation function, it's now returned directly.
    • Ensure Records toString() correctly. #383
    • Iterating over a sliced Seq can no longer cause an infinite recursion. #394
    • Ensure we don't throw when hashing non-extensible object in a modern environment.
    • Fix issue where non-existent function could be called if a collection doesn't have a size.
    Source code(tar.gz)
    Source code(zip)
  • 3.6.4(Mar 8, 2015)

ClojureScript's persistent data structures and supporting API from the comfort of vanilla JavaScript

mori A simple bridge to ClojureScript's persistent data structures and supporting APIs for vanilla JavaScript. Pull requests welcome. Breaking changes

David Nolen 3.4k Dec 31, 2022
Create the next immutable state by mutating the current one

Immer Create the next immutable state tree by simply modifying the current tree Winner of the "Breakthrough of the year" React open source award and "

immer 24.2k Dec 31, 2022
A complete, fully tested and documented data structure library written in pure JavaScript.

Buckets A JavaScript Data Structure Library Buckets is a complete, fully tested and documented data structure library written in pure JavaScript. Incl

Mauricio 1.2k Jan 4, 2023
A simulation data generator

Mock.js Mock.js is a simulation data generator to help the front-end to develop and prototype separate from the back-end progress and reduce some mono

高云 墨智 18.7k Jan 4, 2023
mutate a copy of data without changing the original source

immutability-helper Mutate a copy of data without changing the original source Setup via NPM npm install immutability-helper --save This is a drop-in

Moshe Kolodny 5.1k Dec 29, 2022
JSON-Schema + fake data generators

Use JSON Schema along with fake generators to provide consistent and meaningful fake data for your system. What's next? Breaking-changes towards v0.5.

JSON Schema Faker 2.9k Jan 4, 2023
🛠️construct-js is a library for creating byte level data structures.

??️construct-js is a library for creating byte level data structures.

Francis Stokes 1.3k Dec 14, 2022
HashMap JavaScript class for Node.js and the browser. The keys can be anything and won't be stringified

HashMap Class for JavaScript Installation Using npm: $ npm install hashmap Using bower: $ bower install hashmap You can download the last stable ver

Ariel Flesler 381 Sep 24, 2022
A tiny JavaScript utility to access deep properties using a path (for Node and the Browser)

object-path Access deep properties using a path Changelog 0.11.5 SECURITY FIX. Fix a prototype pollution vulnerability in the set() function when usin

Mario Casciaro 1k Dec 29, 2022
An isomorphic and configurable javascript utility for objects deep cloning that supports circular references.

omniclone An isomorphic and configurable javascript function for object deep cloning. omniclone(source [, config, [, visitor]]); Example: const obj =

Andrea Simone Costa 184 May 5, 2022
Hjson for JavaScript

hjson-js Hjson, a user interface for JSON JSON is easy for humans to read and write... in theory. In practice JSON gives us plenty of opportunities to

Hjson 387 Dec 20, 2022
Immutable persistent data collections for Javascript which increase efficiency and simplicity.

Immutable collections for JavaScript Immutable data cannot be changed once created, leading to much simpler application development, no defensive copy

Immutable.js 32.4k Jan 7, 2023
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
ClojureScript's persistent data structures and supporting API from the comfort of vanilla JavaScript

mori A simple bridge to ClojureScript's persistent data structures and supporting APIs for vanilla JavaScript. Pull requests welcome. Breaking changes

David Nolen 3.4k Dec 31, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Persistent key/value data storage for your Browser and/or PWA, promisified, including file support and service worker support, all with IndexedDB. Perfectly suitable for your next (PWA) app.

BrowstorJS ?? ?? ?? Persistent key/value data storage for your Browser and/or PWA, promisified, including file support and service worker support, all

Nullix 8 Aug 5, 2022
A high-resolution local database that uses precise algorithms to easily record data in local files within a project with persistent JSON and YAML support designed to be easy to set up and use

About A high-resolution local database that uses precise algorithms to easily record data in local files within a project with persistent JSON and YML

Shuruhatik 5 Dec 28, 2022
Serverless for Web3, which is Immutable and Verifiable✅

Tender Layer 2 for IPFS / API Renderer for Web3 / Serverless for Ethereum Tender is dynamic content serving P2P Protocol for Ethereum. V1 Design A Cod

Hyojun Kim 23 Nov 18, 2022