Is is possible to use custom "primitive" types in models? I would like to have "decimal.js" instances as model properties, is there a way to achieve this?
At the moment public API for custom types are'nt exposed yet, since some work on internals is being performed :) Will be available in future! :) I would store that as number, provide a getter that converts to decimal.js and a setter to set the value onto the number property! :)
@timeyr types.refinement(types.string, () => verifyItIsADecimalLookingString) could help a little here, or if you used the boxed class from decimal.js it might work toghether with types.frozen. (Should we allow non-plain objects here @mattiamanzati?)
@mweststrate Non-plain objects are'nt allowed there because if so, MST needed a way to know how to serialize/deserialize types, may become a new type indeed.
check, of course :) types.reference with custom get / set would actually allow that as well btw
Ok, I will watch out for this! :-)
In the meantime, for this concrete usecase I guess I can simply store the decimal value as string on the model and add a computed property that creates a decimal instance from it.
Idea, getter converts from some snapshottable value to a desired value, setter does the inverse.
E.g.:
const MyDecimal = types.reference(
stringvalue => new Decimal(stringValue),
decimal => decimal.toString()
)
const Box = types.model({
height: MyDecimal,
width: MyDecimal
})
Box.create({ height: "7.235234" }).height instanceof Decimal // true
Not sure if types.reference is the best name though, although it can be used to create custom references. Better options are welcome
Yeah, i was wondering why this should be a reference. Up to now, references used to refer to other model types...
But anyway that looks great!
@mweststrate Notice that a parameter that tells the type to store would be required, so something like
const MyDecimal = types.reference(
types.string,
stringvalue => new Decimal(stringValue),
decimal => decimal.toString()
)
const Box = types.model({
height: MyDecimal,
width: MyDecimal
})
Box.create({ height: "7.235234" }).height instanceof Decimal // true
Also, that type will be immutable, or we can let the user return a subscription whenever it changes and emit a replace snapshot.
const MyDecimal = types.reference(
types.string,
stringvalue => new Decimal(stringValue),
decimal => decimal.toString()
listener => {
const fn = newValue => listener(newValuie)
decimal.on('change', fn)
return () => decimal.off('change', fn)
}
)
const Box = types.model({
height: MyDecimal,
width: MyDecimal
})
Box.create({ height: "7.235234" }).height instanceof Decimal // true
No, I think it should be considered immutable indeed, like normal
references, even though the target is mutable, that doesn't matter in the
sense that processing changes inside the tharget is the targets
responsibility, and not of the reference pointing to it.
Op ma 12 jun. 2017 om 10:37 schreef Mattia Manzati <[email protected]
:
@mweststrate https://github.com/mweststrate Notice that a parameter
that tells the type to store would be required, so something likeconst MyDecimal = types.reference(
types.string,
stringvalue => new Decimal(stringValue),
decimal => decimal.toString()
)const Box = types.model({
height: MyDecimal,
width: MyDecimal
})Box.create({ height: "7.235234" }).height instanceof Decimal // true
Also, that type will be immutable, or we can let the user return a
subscription whenever it changes and emit a replace snapshot.const MyDecimal = types.reference(
types.string,
stringvalue => new Decimal(stringValue),
decimal => decimal.toString()
listener => {
const fn = newValue => listener(newValuie)
decimal.on('change', fn)
return () => decimal.off('change', fn)
}
)const Box = types.model({
height: MyDecimal,
width: MyDecimal
})Box.create({ height: "7.235234" }).height instanceof Decimal // true
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/mobxjs/mobx-state-tree/issues/172#issuecomment-307725340,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABvGhFB3GKoD_pVD-Ei3HQlFD_7S80d8ks5sDPjWgaJpZM4NyWyf
.
I'd say it is an adapter or transform rather than a reference
I suggest types.custom instead of types.reference.
suggestion with adapted example from @mattiamanzati
// @example
const isNumber = x => typeof x === 'number'
const isString = x => typeof x === 'string'
const isStringOrNumber = x => isString(x) || isNumber(x)
const hasDecimals = x => isStringOrNumber(x) ? x % 1 === 0 : false
const toNumber = x => +x
const toDecimal = x => hasDecimals(x) ? toNumber(x).toPrecision(2) : 0
const DecimalType = types.reference(
types.string,
(stringValue) => toDecimal(stringValue),
(decimal) => decimal.toString(),
(decimal, listener) => {
const fn = newValue => listener(newValue)
decimal.on('change', fn)
return () => decimal.off('change', fn)
}
)
/**
* @see https://github.com/codemix/flow-runtime/tree/master/packages
* @see https://github.com/gcanti/tcomb
* @see https://github.com/sanctuary-js/sanctuary-def
* @see https://github.com/mobxjs/mobx/tree/master/src/types
*
* @param {Object} typeObj mstTypeOrCustomObj
* @param {Function} coerceFromSnapshot
* @param {coerceToSnapshot} coerceToSnapshot
* @param {eventEmitter} eventEmitter
* @return {MobxStateTreeTypeDefinition}
*/
const customType = (typeObj, coerceFromSnapshot, coerceToSnapshot, eventEmitter) => {}
/**
* @desc would be customType, as-an-object
* @see customType
* @param {Object} config CustomTypeObject
* @return {MobxStateTreeTypeDefinition}
*/
const customTypeFrom = config => {
const result = {}
if (config.type) result.type = config.type
else if (config.typeName) result.type = {typeName: config.typeName}
if (config.fromSnapshot) result.fromShapshot = config.fromShapshot
if (config.toSnapshot) result.toSnapshot = config.toSnapshot
if (config.emitter) result.eventEmitter = config.emitter
return customType.apply(null, Object.values(config))
}
things to consider
const EhType = {
// * -> boolean
checker: Function,
// compat with existing type systems
typeName: String('Eh'),
// this also could be `toType`
fromSnapshot: Function,
// this could be `fromType`
toSnapshot: Function,
// @alias onChange
emitter: Function,
}
types.addTypeFrom(EhType)
const T = () => true
types.addType('Eh', t, t, t)
// types.updateType('array', checker, fromSnapshot, toSnapshot, emitter)
// types.updateTypeFrom({})
Custom references are out as of 1.2.0!
While this seems to be a good addition, to me it looks like it does not solve my original use case where I wanted to have Decimal instances within my models. The new reference type API seems to require that the custom type implements IType<any, T>, right? So this won't work with arbitrary classes.
Correct, that can currently not be done cleanly yet. It is in progress
though :)
Op di 2 jan. 2018 om 20:33 schreef Tim Meyer notifications@github.com:
While this seems to be a good addition, to me it looks like it does not
solve my original use case where I wanted to have Decimal instances within
my models. The new reference type API seems to require that the custom type
implements IType, right? So this won't work with arbitrary
classes.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/mobxjs/mobx-state-tree/issues/172#issuecomment-354855337,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABvGhCunCNddZMOem3AZ-5C8Se88QH9jks5tGoR7gaJpZM4NyWyf
.
Most helpful comment
Custom references are out as of 1.2.0!