First, if you are not familiar with this pattern, I recommend you read this excellent article.
Our Master-Class types include an M.State
type. That type helps us turn objects into concurrent, hierarchical state machines.
The M.State
type basically merges object types together
let MyClass = M({
state: M.State([
{
delegate: M({n: 3}), // (1) first object type
subState: [{
delegate: M({m: 5}) // (1.1) first object type child
}]
},
{
delegate: M({s: String}) // (2) second object type
}
])
});
let myInstance = new MyClass();
assert.deepEqual(myInstance.state, {n: 3, m: 5, s: ''});
but every merge can be conditional using the when
option
MyClass = M({
flag1: true,
state: M.State([
{
when() {return this.flag2;},
delegate: M({n: 3}), // (1) first object type
subState: [{
when() {return this.root.flag1;},
delegate: M({m: 5}) // (1.1) first object type child
}]
},
{
delegate: M({ // (2) second object type
flag2: Boolean,
s: String
})
}
])
});
myInstance = new MyClass();
assert.deepEqual(myInstance.state, {flag2: false, s: ''});
Note that myInstance.state.m
property is not included, even though this.root.flag1
is true
. This is because its parent state is blocked on this.flag2
. Now, if we just assign myInstance.state.flag2 = true
, we'll get
assert.deepEqual(
myInstance.state,
{flag2: true, s: '', n: 3, m: 5}
);