Skip to content

Instantly share code, notes, and snippets.

@jamonholmgren
Created August 9, 2022 08:03
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 jamonholmgren/1402b25e8831b1a8eeff3a2a534532e7 to your computer and use it in GitHub Desktop.
Save jamonholmgren/1402b25e8831b1a8eeff3a2a534532e7 to your computer and use it in GitHub Desktop.

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")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment