Code Monkey home page Code Monkey logo

typed-immutable's Issues

List.map does not work with mapper that returns null or undefined

Example:

var {Record, List} = require("typed-immutable");

var Point = Record({x: Number(0), y: Number(0)})
var Points = List(Point, "Points")
ps = Points.of({x:3}, {y: 5})
ps.map(a => a.x || null);

this throws a "TypeError: Cannot read property 'constructor' of null"

I believe what is happening here is that the type inferer is not correctly returning a new List(Maybe(Number)).

Support for Enumerable fields

Im proposing somethings like custom type Called Enum
(I didnt test this)

const Enum = (values) =>{
  if (typeof(values) !== 'array') {
    return TypeError(`"${value}" is not an array`);
  }
  const map = {};
  values.each((val) => {
    map[val] = val;
  });
  var validValues = values.toString();

  return Typed(`Enum(${ validValues})`, value => {
    if (!map[value]){
      return TypeError(`"${value}" in ${validValues}`);
    }
    return value
  })
}

var enRecord = Record({
  enumField: Enum(['A','B'])
})

enRecord.set('enumField', 'B') //Succeed
enRecord.set('enumField', 'C') //Throw an Error

Is there any other workarounds to this?

Symbol polyfill overwrites native Symbol type in typed.js

The polyfill for Symbol (https://github.com/typed-immutable/typed-immutable/blob/master/src/typed.js#L3) always overwrites the native Symbol type since the var declaration is hoisted outside of the if statement, so that polyfill actually will act as the following:

var Symbol
if (typeof(Symbol) === 'undefined') {
  Symbol = hint => `@@${hint}`
  Symbol.for = Symbol
}

This means that you cannot use Symbol as a type, i.e. Map(Symbol, String) will fail.

New maintainer is needed

I am afraid I do not have time to work on this project, so if someone want's to step up and move it forward review / land pull requests respond to issues etc.

Handle recursive types?

Is there any way to handle recursive types? I.e.

import {Record, List} from 'typed-immutable';

var Node = Record({
    data: String,
    subNodes: List(Node)
});

One can't do the above, as Node is not defined yet, when defining subNodes. Is there a way to accomplish this now, or do you have plans for this capability?

One possibility would be to add a constant, say "CurrentType", that would tell Record to use it's type for that member when creating new records. I.e.:

import {Record, List, CurrentType} from 'typed-immutable';
var Node = Record({
    data: String,
    subNodes: List(CurrentType)
});

Thoughts?

[feature] Adding functions to types for derived data?

I'm somewhat new to react/redux and have been struggling with how to handle "derived data." A trivialized example is given raw data like

let person = {first: 'Bob', last: 'Fish'}

what is the appropriate way to define person.fullName? Or should I just have personUtils.fullName(person)? It seems if I were to use typed-immutable to define the structure of my data I could also define methods/ property-getters to define derived data.

Good idea/ bad idea?

setSize may only downsize

While using this library with immutable-js, we are encountering a typedError "setSize may only downsize".
But there could be cases in which list size might increase. Why there is this restriction of downsize?

Better error messages

After using typed-immutable on multiple projects now the biggest problem that comes up is tracking down why a type error occurs - particularly when restoring a large nested structure from a raw JS object.

As an example:

const Address = Record({
  line1: String,
  city: String,
  country: String,
});

const Person = Record({
  id: Number,
  name: String,
  email: String,
  age: Number,
  address: Address,
});

const People = new Map(Number, Person);

new People([[1, { 
  id: 1,
  name: 'Bob',
  email: '[email protected]',
  age: 100,
  address: {
    line1: 5,
  }
}]]);

currently gives an error

TypeError: Invalid value: Invalid value for "address" field:
 Invalid value for "line1" field:
 "undefined" is not a string

This is ok when you have the context and know what structures it's referring to be in many cases you don't or the fields are generic enough that it's hard to identify where it comes from. It's also very useful to know the data that failed.

I've been looking at improving them, eg. the above is now:

    TypeError: Entry in Map(Number, Person) failed to satisfy value type:

    Key:
    1

    Value:
    {
      "id": 1,
      "name": "Bob",
      "email": "[email protected]",
      "age": 100,
      "address": {
        "line1": 5
      }
    }

    Failed to create instance of Person

      Value for field 'address' must satisfy type 'Address'

    Failed to create instance of Address

      Value for field 'line1' must satisfy type 'String'

    Invalid value: "5" is not a string

My only concern with adding this is that it will be a bit slower to generate this level of detail (eg. doing a JSON.stringify on value). In my use cases so far it wouldn't matter as I never catch the TypeError's - if they occur it's a bug that we fix.

Does anyone have any thoughts about this? Should it be opt in? Am I overthinking it? I also haven't measured anything yet - I think it may only become a problem if you were generating a lot of these (eg. iterating a large list attempting to instantiating record's and handling any errors).

@lukesneeringer @stutrek @udnisap

Consider adding type coercion

It'd be nice to be able to coerce convertible types to other types.

const PersonRecord = Record({
  id: String,
  phone: Coerce(Union(Number, String), String),
}, 'Person');

In this hypothetical example if we did the following:

const p1 = PersonRecord({ id: 0, phone: 12318001800 });

accessing p1.phone would give us a string.

We'd have to keep a map of how we get from one type to others. This could be hard-coded or supplied at run-time.

Minor release

@stutrek @davecoates @udnisap

I have gone through today and tried to do "low hanging fruit" things, and move along the pull requests. We now only have three that are active, and two should be merged soon. Once #18 and #29 are merged, which can hopefully be in a couple of days, I would like to do a release.

I will write up a changelog and such and make a pull request beforehand, so everyone will be able to see it. Does anyone have any objections to this?

Switch on Union type

Hello,
thanks for this useful library !
Is it possible to switch/if/match on an Union type to determine the underlying concrete type ?

Add functions?

Any plans to supports function signatures as parameters to a record? and maybe enums as well?

Reconsider duck typing records

At the moment if you define types with a following signatures:

const X = Record({x: 0}, 'X')
const Y = Record({y: 0}, 'Y')

const C = Record({ data: Union(X, Y) })

Then type union interprets data value not always as one would expected:

C({data: {x: 2}}) // => Typed.Record({data: Union(X, Y)})({ "data": X({ "x": 2 }) })
C({data: X({x: 5})}) // => Typed.Record({data: Union(X, Y)})({ "data": X({ "x": 5 }) })
C({data: Y({y: 3})}) // => Typed.Record({data: Union(X, Y)})({ "data": Y({ "y": 3 }) })

C({data: {y: 2}}) // => Typed.Record({data: Union(X, Y)})({ "data": X({ "x": 0 }) })

Most likely in last statement data field was expected to be an instance of Y instead of X, although given that {y: 2} can be read both as X and Y it was interpreted as a first type in the union X.

It maybe better to disallow passing untyped values all together in order to avoid this issue.

flatMap doesn't work

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()

Typed data must carry type information

At the moment if you define types with a following signatures:

const X = Record({x: 0}, 'X')
const Y = Record({y: 0}, 'Y')

const C = Record({ data: Union(X, Y) })

Then type union interprets data value not always as one would expected:

C({data: {x: 2}}) // => Typed.Record({data: Union(X, Y)})({ "data": X({ "x": 2 }) })
C({data: X({x: 5})}) // => Typed.Record({data: Union(X, Y)})({ "data": X({ "x": 5 }) })
C({data: Y({y: 3})}) // => Typed.Record({data: Union(X, Y)})({ "data": Y({ "y": 3 }) })

C({data: {y: 2}}) // => Typed.Record({data: Union(X, Y)})({ "data": X({ "x": 0 }) })

Most likely in last statement data field was expected to be an instance of Y instead of X, although given that {y: 2} can be read both as X and Y it was interpreted as a first type in the union X. While this is bad (see #2) it does not seem to be a common issue in my experience.

What happens far more often in my experience is that new type is defined which supposed to be added to a type union (but for whatever reasons it was not added to type union):

const Z = Record({ z: 0 })

C({data: Z({z: 5})}) // => Typed.Record({data: Union(X, Y)})({ "data": X({ "x": 0 }) })

Now surprise and a problem is far worse in this case, as passed data field had a type but it got casted to a completely different type. There is also no simple way to avoid or spot this issue.

Type checking task

Really nice project.

One of the main benefits to having types in code is that during compile time (or during your transpiling process) you can be warned of places where you have set the wrong type or called using the wrong type.

Typescript for example will warn you if you do something like:

Point({x: "1", y: 1});

The above will output an error explaining you have used a string instead of number type.

Would building a task to check the codes type safety be within the scope of this project?

Maybe using esprima and the parsing down the tree?

It's something I might try and help with if you feel it's within the scope, but thought I would ask as it would be good to get your opinions on this before starting extra work on this.

Add pattern matching

Currently used patten in most code is something along these lines:

const Model = Record({value: Number})

const Increment = Record({label: '+'});
const Decrement = Record({label: '-'});
const Action = Union(Increment, Decrement);

const update = (model, action) =>
  action instanceof Increment ? model.update('value', x => x + 1) :
  action instanceof Decrement ? model.update('value', x => x - 1) :
  model;

With a pattern matching it should be possible to turn it to something like this:

const update = Match(Match._, Match.pattern)
  .case(Increment, (model, _) => model.update('value', x => x + 1))
  .case(Decrement, (model, _) => model.update('value', x => x + 1))
  .default((model, _) => model)

React PropType validations

Hi,

I'm using typed-immutables in a react project. I have a type called Card and it's passed as a prop to CardComponent. Similarly there's CardList and CardListComponent

const Card = Record({
  id: String,
  title: String
}, 'Card')

export const CardList = List(Card, 'CardList') 

export default Card

How would I validate them with react PropTypes? Are there any methods that I can use, that go as follows

const CardComponent = (card) => {
  return (
    <div>${card.title}</div>
  )
}

CardComponent.propTypes = {
  card: Card.isRequired // or Card.isOptional
}

How do I go about doing those validations now? Validations for CardList seem to be harder. What would be a good way to implement these validations?

Process discussion

@stutrek @davecoates @udnisap

I have merged #24 and we now have automated testing on all pull requests. I also set up master as a protected branch in GitHub, which means it is no longer possible to push to it directly; anything has to be a pull request and Travis tests must pass.

I have not set up Travis to auto-publish to npm. I can do that if we want, although I might want some coaching from @udnisap about the right way to do that.

I also think it would be useful to have a couple of process discussions. What should our rule on PR merging be? This is a pretty small project, so I think that, in general, the rule should be a +1 from any other person.

I would also like to take a pass through the code and add more commenting (and probably a linter), as well as do a thorough sweep through the documentation. Would that be something that you all would welcome, or find annoying?

Finally, would it be valuable to have a (presumably low volume) Slack (or similar) channel, or do we want to continue to use GitHub for discussion? I know I am not always the best at checking GitHub; not sure if that is a concern for others.

Support for Map

I noticed there seems to be support for Map but it's not documented anywhere and has to be imported from 'typed-immutable/lib/map'. Any reason for that (ie. experimental, has issues)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.