This was a late-night forey into trying to improve on MobX-State-Tree's ergonomics and implementation.
MST is pretty good.
type MSTActions = {
[key: string]: Function
}
type MSTViews = {
[key: string]: any
}
type MSTVolatile = {
[key: string]: Function
}
type MSTProps = {
[key: string]: unknown
}
interface MSTModel {
name: string
properties?: MSTProps
actions?: (self: ReturnType<typeof create>) => MSTActions
views?: (self: ReturnType<typeof create>) => MSTViews
volatile?: (self: ReturnType<typeof create>) => MSTVolatile
}
function create<T extends MSTModel>(
model: T,
properties: { [key in keyof T["properties"]]: T["properties"][key] }
) {
const instance = {
...properties
}
const actions = model.actions?.(instance) || {}
const views = model.views?.(instance) || {}
const volatile = model.volatile?.(instance) || {}
Object.assign(instance, {
...actions,
...views,
...volatile
})
return instance
}
const mst = {
string: "",
number: 0,
boolean: false,
array: [],
object: {},
date: new Date()
}
const MyModel = {
name: "Jamon",
properties: {
firstName: mst.string,
lastName: mst.string
},
actions: (self) => ({
setFirstName: (newName: string) => {
self.firstName = newName
},
doSomething() {
return "waddup"
}
}),
views: (self) => ({
get fullName() {
return self.firstName + " " + self.lastName
}
})
}
const myModel = create(MyModel, {
firstName: "Jamon",
lastName: "Holmgren"
})
// myModel.firstName
myModel.setFirstName("Joe")