typed-immutable / typed-immutable

Immutable and structurally typed data
MIT License
263 stars 14 forks source link

flatMap doesn't work #11

Closed davecoates closed 8 years ago

davecoates commented 9 years ago

Calling flatMap on a List doesn't work. Can get around it by just doing a map then a flatten.

var {Record, List} = require("typed-immutable")
var Item = Record({
    ids: List(Number)
});

var Items = List(Item);
var a = new Item({ids: [1,2,3,4]})
var b = new Item({ids: [5,6]})
var items = new Items([a, b])

// Array [1, 2, 3, 4, 5, 6]
items.map(item => item.ids).flatten().toJS(); 
// doesn't work
// TypeError: Invalid value: Invalid data structure "1" was passed to Typed.Record({ids: Typed.List(Number)})
items.flatMap(item => item.ids).toJS()

// Using immutable List directly works
var immutable = require('immutable');
items = immutable.List([a,b]);
// Array [1, 2, 3, 4, 5, 6]
items.flatMap(item => item.ids).toJS()
Gozala commented 9 years ago

@davecoates thanks for the report.

I think there is an error in your code snippet since your comment does suggest that map then flatten works which is also my observation:

items.map(function(item) { return item.ids }).flatten().toJS()
[ 1, 2, 3, 4, 5, 6 ]

Now as of the problem issues is that operation on list, happen through immutable.js that uses type of the value to produce a result. Which means that if you perform operation on List(T) return value will also be List(T) which causes a type error as in this case result is List(Number) an that is what type error you see is about:

TypeError: Invalid value: Invalid data structure "1" was passed to Typed.Record({ids: Typed.List(Number)})

In other words it expects to return list of Items but encounter number and there for errors.

That being said .map operation get's special treatment as mapping is usually type transformation operation from a type to b type & to handle that library uses special TypeInferredList in order to detect the type of the returned list. I guess I forgot that flatMap is similar and there for required same treatment.

It is also a mystery why .flatten works as it produces List(T) from List(List(T)), my guess is immutable.js (which is what all typed-immutable types inherit from) list just concatenates all lists onto first one and there for return is expected to be of the same type as first so things just work as expected.

@davecoates would you be willing to work on the fix which will be matter of adding custom flatMap method pretty equivalent of pointed out map method.

davecoates commented 9 years ago

Thanks for the explanation, makes sense. I will hopefully look at a fix over the weekend

Gozala commented 8 years ago

Unfortunately I am no longer able to maintain this project, I apologize. If someone wishes to step up and take leadership of this project please respond to #21