Skip to content

Instantly share code, notes, and snippets.

@mizchi
Last active December 15, 2018 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mizchi/bdaa2250f1707d6fb09f4115644da0aa to your computer and use it in GitHub Desktop.
Save mizchi/bdaa2250f1707d6fb09f4115644da0aa to your computer and use it in GitHub Desktop.
// impl
type AnyMsg = {
msg: string;
};
type AnyCmd = {
cmd: string;
next: (...args: any) => Msg;
};
class Platform<Model, Msg extends AnyMsg, Cmd extends AnyCmd> {
_queue: Array<Msg | Cmd> = [];
constructor(
public _model: Model,
public _update: (model: Model, msg: Msg) => [Model, Cmd | null]
) {}
getModel(): Model {
return this._model;
}
dispatch(msg: Msg | Cmd) {
this._queue.push(msg);
this._drainQueue();
}
_drainQueue() {
if (this._queue.length === 0) {
return;
}
const [newQueue, ...restQueue] = this._queue;
this._queue = restQueue;
let currentCmd: Cmd | null = null;
if ((newQueue as any).msg) {
const [nextModel, newCmd] = this._update(this._model, newQueue as Msg);
this._model = nextModel;
currentCmd = newCmd;
} else {
currentCmd = newQueue as Cmd;
}
if (currentCmd) {
const newMsg = currentCmd.next();
this._queue.push(newMsg as Msg);
}
this._drainQueue();
}
}
type Model = {
face: number;
history: Array<number>;
};
// msg
function roll(): {
msg: "roll";
} {
return {
msg: "roll"
};
}
function newFace(
n: number
): {
msg: "newFace";
payload: number;
} {
return {
msg: "newFace",
payload: n
};
}
type Msg = ReturnType<typeof roll> | ReturnType<typeof newFace>;
// cmd
function random(
next: (n: number) => Msg
): {
cmd: "random";
next: () => Msg;
} {
return {
cmd: random.name as "random",
next() {
return next(Math.floor(Math.random() * 10));
}
};
}
type Cmd = ReturnType<typeof random>;
const init = () => ({
face: 0,
history: [0]
});
function update(model: Model, msg: Msg): [Model, Cmd | null] {
switch (msg.msg) {
case "roll": {
return [model, random(newFace)];
}
case "newFace": {
return [
{ face: msg.payload, history: [msg.payload, ...model.history] },
null
];
}
default: {
return [model, null];
}
}
}
const platform = new Platform<Model, Msg, Cmd>(init(), update);
platform.dispatch(roll());
platform.dispatch(roll());
console.log("model", platform.getModel());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment