Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Adding functions to types for derived data? #7

Closed
thom-nic opened this issue Oct 5, 2015 · 2 comments
Closed

[feature] Adding functions to types for derived data? #7

thom-nic opened this issue Oct 5, 2015 · 2 comments

Comments

@thom-nic
Copy link

thom-nic commented Oct 5, 2015

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?

@Gozala
Copy link
Collaborator

Gozala commented Oct 5, 2015

@thom-nic with Record types you could define Person type like in the example below. Defined records will have all the getters for fields defined:

const Person = Record({first: String, last:String})

const bob = Record({first: 'Bob', last: 'Fish'})

bob.first // => 'Bob'
bob.last // => 'Fish

As of computed field like fullName I personally like to use plain functions:

fullName = ({first, last}) => `${first} ${last}`

I used to put such functions as a static methods of the Record constructor Person.fullName = fullName just for grouping, but I ditched that practice and tend to group functions into modules instead.

You could also define them as methods on the prototype if you like:

const asMethod = f => function(...args) => {f(this, ....args)}
Person.prototype.fullName = asMethod(fullName)

That is sometimes useful if you want a polymorphism behavior, although for that I still tend to use method library or if I don't want pull in extra library then this pattern:

const slice = (value, from, to) => value.constructor[$slice](value, from, to)
$slice = slice.symbol = Symbol.for('mylib/slice') 

MyType[slice.symbol] = (myType, from, to) => /*... */
MyOtherType[slice.symbol] = (myOtherType, from, to) => /*... */

I prefer functions because:

  1. I like to keep data separate from operations that can be performed on it. That way all operations are equal no first class second class.
  2. Functions are more convenient for functional compositions and with high order functions like .map
    .filter etc...

Ultimately I think it's really just matter of personal preference and does not really matter.

@Gozala
Copy link
Collaborator

Gozala commented Oct 5, 2015

Oh and I don't personally like property getters for computed properties as I think they live an impression of being regular property while under the hood they do run code that may cause side-effects throw exception etc.. I much rather prefer to be able to distinguish computation from property access while reading a code without having to digg into implementations.

P.S. Record do use getters under the hood though, primarily so that they would throw exceptions at you if you try to mutate them and to make assignment possible on .asMutable() API.

@Gozala Gozala closed this as completed Oct 5, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants