{"id":2052,"date":"2016-10-25T20:27:07","date_gmt":"2016-10-26T01:27:07","guid":{"rendered":"https:\/\/www.wiredprairie.us\/blog\/?p=2052"},"modified":"2016-10-25T20:27:07","modified_gmt":"2016-10-26T01:27:07","slug":"mobx-and-typescript-experiement","status":"publish","type":"post","link":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/2052","title":{"rendered":"MobX and TypeScript Experiement"},"content":{"rendered":"

I wanted to give MobX a try, in particular from TypeScript.<\/p>\n

Here\u2019s my first attempt. I liberally used the documentation example found within\u00a0createTransformer<\/a>\u00a0as my guide.<\/p>\n

[javascript]<\/p>\n

import "core-js";
\nimport { observable, autorun, createTransformer } from "mobx";<\/p>\n

\/*
\n The store that holds our domain: boxes and arrows
\n*\/<\/p>\n

class Store implements Storable {
\n @observable public boxes: Box[];
\n @observable public arrows: Arrow[];
\n @observable public selection: any;<\/p>\n

constructor(init: Storable = {}) {
\n this.boxes = init.boxes || [];
\n this.arrows = init.arrows || [];
\n this.selection = init.selection;
\n }
\n}<\/p>\n

interface Storable {
\n boxes?: any[];
\n arrows?: Arrow[];
\n selection?: any;
\n}<\/p>\n

interface Box {
\n id: string;
\n caption?: string;
\n}<\/p>\n

interface Arrow {
\n id: string;
\n to?: Box;
\n from?: Box;
\n}<\/p>\n

const serializeState = createTransformer&lt;Store, Store&gt;(store =&gt; {
\n return new Store({
\n boxes: store.boxes.map(serializeBox),
\n arrows: store.arrows.map(serializeArrow),
\n selection: store.selection ? store.selection.id : null
\n });
\n});<\/p>\n

\/\/ copy using Object.assign (as this is just a simple JS object anyway)
\nconst serializeBox = createTransformer&lt;Box, Box&gt;(box =&gt; Object.assign({}, box));<\/p>\n

const serializeArrow = createTransformer&lt;Arrow, Arrow&gt;(arrow =&gt; {
\n \/\/ or can copy manually…
\n console.log("serializeArrow"); \/\/ this is only called 3 times!
\n return {
\n id: arrow.id,
\n to: arrow.to,
\n from: arrow.from
\n };
\n});<\/p>\n

const store = new Store();
\nconst states: Storable[] = [];<\/p>\n

autorun(() =&gt; {
\n \/\/ this could be used to create an undo buffer, or whatever
\n \/\/ probably wouldn’t want infinite growth … :)
\n states.push(serializeState(store));
\n});<\/p>\n

const b1 = { id: "b1", caption: "Box 1" };
\nconst b2 = { id: "b2", caption: "Box 2" };
\nconst b3 = { id: "b3", caption: "Box 3" };
\nstore.boxes.push(b1);
\nstore.boxes.push(b2);
\nstore.boxes.push(b3);<\/p>\n

store.arrows.push({ id: "a1", from: b1, to: b2 });
\nstore.arrows.push({ id: "a2", from: b1, to: b3 });
\nstore.arrows.push({ id: "a3", from: b2, to: b3 });
\nb1.caption = "Box 1 – Edited";<\/p>\n

\/\/ Should be 8
\nconsole.log(states.length);<\/p>\n

b1.caption = "Box 1 – Final";<\/p>\n

\/\/ Should be 9
\nconsole.log(states.length);
\n[\/javascript]<\/p>\n

To make that work:<\/p>\n

[plain]<\/p>\n

npm install –S mobx reflect-metadata
\nnpm install –D @types\/core-js<\/p>\n

[\/plain]<\/p>\n

Sweet that MobX includes a TypeScript declarations file. :)<\/p>\n

The things of interest here is that MobX assists in maintaining a stack of the object graph’s state, something that could be used for example in an undo buffer or comprehensive log system.<\/p>\n

In this example, that’s done by using the MobX\u00a0autorun<\/strong><\/a>\u00a0functionality. When\u00a0any of the dependencies of autorun changes, the function executes. In the example above, it makes a clone of the current store, using the createTransformer<\/a><\/strong>\u00a0function, which turns a function into a reactive and memoizing function. Through memoization, it only transforms portions of the objects that have changed, not everything, every time. That doesn’t mean that you won’t want to limit the growth of the states, but you shouldn’t worry that a large complex object structure is being built with every change.<\/p>\n

As TypeScript doesn’t support the object spread operator (which is convenient for making a clone of an object), I’ve used\u00a0Object.assign<\/strong> instead (which may require a polyfill depending on the environment in which you use this code).<\/p>\n

 <\/p>\n

 <\/p>\n","protected":false},"excerpt":{"rendered":"

I wanted to give MobX a try, in particular from TypeScript. Here\u2019s my first attempt. I liberally used the documentation example found within\u00a0createTransformer\u00a0as my guide. [javascript] import "core-js"; import { observable, autorun, createTransformer } from "mobx"; \/* The store that holds our domain: boxes and arrows *\/ class Store implements Storable { @observable public boxes: […]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[4],"tags":[168,167],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pd5QIe-x6","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":2241,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/2241","url_meta":{"origin":2052,"position":0},"title":"TS2688 with TypeScript, React Native, and MobX","date":"March 1, 2018","format":false,"excerpt":"To\u00a0preserve my sanity if I should run into this again....\u00a0 I created a React Native project, ejected it, and then converted it to use TypeScript. Things were going well until I started to use MobX. The following error occurred: node_modules\/mobx\/lib\/utils\/utils.d.ts(1,23): error TS2688: Cannot find type definition file for 'node'. Something\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1563,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1563","url_meta":{"origin":2052,"position":1},"title":"Knockout.JS: AsDictionary","date":"March 9, 2012","format":false,"excerpt":"I frequently find that I have an array of objects in JavaScript that I want to display in a particular order and also have the ability to quickly locate an object by an ID or a key (and not use the indexOf function). As my recent project is using Knockout.JS,\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2012\/03\/image3.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":1164,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1164","url_meta":{"origin":2052,"position":2},"title":"Making Android development a little more like Microsoft development","date":"January 9, 2011","format":false,"excerpt":"By day, I mostly use Microsoft development tools, and have used them for YEARS. I\u2019ve been experimenting with some Android development recently, and was annoyed by several missing handy tricks that Microsoft tools have done for years. So, I just coded one replacement. Commonly, in Microsoft platforms, when you create\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"All aboard the Android train!","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2011\/01\/image.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2211,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/2211","url_meta":{"origin":2052,"position":3},"title":"Flutter.io First Impressions","date":"February 22, 2018","format":false,"excerpt":"I've been tinkering with Flutter.io for a few days now and wanted to document a few early impressions. It uses the programming language Dart. I'd looked at a lot of Dart code when it was first announced, but hadn't looked at it much since. I couldn't see it gaining meaningful\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"Dart home page, May 2018","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2018\/02\/2018-02-22-07_23_39-Dart-programming-language-_-Dart.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1701,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1701","url_meta":{"origin":2052,"position":4},"title":"Windows 8 WinRT\/Metro Missing UpdateSourceTrigger","date":"August 5, 2012","format":false,"excerpt":"If you\u2019ve done WPF or Silverlight programming, you may have found an occasion where using the Binding property UpdateSourceTrigger set to PropertyChanged was extremely useful. (I know I have!) It may have looked something like this: The key feature was the live updating of the\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":388,"url":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/388","url_meta":{"origin":2052,"position":5},"title":"Silverlight Weather Demonstration","date":"June 26, 2008","format":false,"excerpt":"Demonstration available here. (You'll need to wait for a moment while it loads the first time). I've created a reasonably simple, yet multi-technology (and discipline) demonstration using Silverlight for the user interface and ASP.NET as the back-end. The demonstration uses: Silverlight 2.0 Data binding Delayed downloading of images \"Web services\"\u2026","rel":"","context":"In "Coding"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.wiredprairie.us\/blog\/wp-content\/uploads\/2008\/06\/image21.png?resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts\/2052"}],"collection":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/comments?post=2052"}],"version-history":[{"count":12,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts\/2052\/revisions"}],"predecessor-version":[{"id":2064,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/posts\/2052\/revisions\/2064"}],"wp:attachment":[{"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/media?parent=2052"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/categories?post=2052"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wiredprairie.us\/blog\/index.php\/wpjson\/wp\/v2\/tags?post=2052"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}