Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable.fromJS() is not deep

The description of Immutable.fromJS is:

Deeply converts plain JS objects and arrays to Immutable Maps and Lists.

But that's wrong. I have an object with the following structure. The capitalized items are ES6 classes.

Foo
  prop1
  prop2
  bars
    Bar
      prop1
      prop2
    Bar
      prop1
      prop2
  bazes
    Baz
      prop1
      prop2
      bars
        Bar
          prop1
          prop2
        Bar
          prop1
          prop2
    Baz
      prop1
      prop2
      bars
        Bar
          prop1
          prop2
        Bar
          prop1
          prop2

The result of Immutable.fromJS(foo) is a Map. The arrays bars and bazes are Lists. However, each element of these lists is still a plain (ES6) object. The bars property of each Baz is an array, not a list.

Am I doing something wrong, or is the documentation incorrect?

Maybe the deep feature is not supported for ES6 objects? If that's the case, how can I make my object deeply immutable?

UPDATE:

This works but feels kinda gross: Immutable.fromJS(JSON.parse(JSON.stringify(foo)))

like image 703
Tim Scott Avatar asked Apr 29 '26 07:04

Tim Scott


1 Answers

The very first sentence in the docs for fromJS is:

Deeply converts plain JS objects and arrays to Immutable Maps and Lists.

If Foo, Bar, and Baz are ES6 classes then they are neither plain JS objects nor arrays—they're instances of a class. So, no, the docs are not incorrect.

As an aside, if Immutable.fromJS automatically converted any object it encountered into a plain JS object, as you seem to have expected it to, that would be very surprising behavior to most users, and not at all desirable.

But since that's the behavior you want, you'll be happy to know that the Immutable wiki has a section on this exact topic, which I'll duplicate here for posterity:

Here is an example which will convert any Object, including exotic Objects, to Immutable.Map:

function fromJSGreedy(js) {
  return typeof js !== 'object' || js === null ? js :
    Array.isArray(js) ? 
      Immutable.Seq(js).map(fromJSGreedy).toList() :
      Immutable.Seq(js).map(fromJSGreedy).toMap();
}

That's pretty simple. And, indeed, it works exactly as promised, as you can see by running the below snippet.

class Foo {
  constructor(name, ...children) {
    this.name = name;
    this.children = children;
  }
}

class Bar extends Foo {}
class Baz extends Foo {}

const myBar = new Bar("myBar", new Baz("myBaz1"), new Baz("myBaz2"));
const myFoo = new Foo("myFoo", myBar);

function fromJSGreedy(js) {
  return typeof js !== 'object' || js === null ? js :
    Array.isArray(js) ? 
      Immutable.Seq(js).map(fromJSGreedy).toList() :
      Immutable.Seq(js).map(fromJSGreedy).toMap();
}

console.log(fromJSGreedy(myFoo).toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>
like image 159
Jordan Running Avatar answered Apr 30 '26 19:04

Jordan Running



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!