Simplifying message/event checks in Bubbletea for Golang

Originally posted on 2023-01-03

I’ve been working on learning Bubbletea lately and I’ve hit into a pattern that was annoying me. I had a bunch of messages that would all need to trigger one action (along with other things they might do).

I tried creating a flag and then running the operation if the flag was set but it was ugly. I tried just running the operation for each message but it was also ugly.

switch typedMsg := untypedMsg.(type) {
	case Message1:
		m.table = rebuildTable()
	case Message2:
		m.table = rebuildTable()
	case Message3:
		m.table = rebuildTable()
	case Message4:
		m.table = rebuildTable()
	case Message5:
		m.table = rebuildTable()

...

Finally I settled on using an array of empty structs like this:

var (
	TableRebuildEvents = []tea.Msg{
		Message1{},
		Message2{},
		Message3{},
		Message4{},
		Message5{},
	}
)

Then I have a function that checks to see if the message is in that array:

func isTableRebuildMessage(message tea.Msg) bool {
	for _, t := range TableRebuildMessage {
		if reflect.TypeOf(message) == reflect.TypeOf(t) {
			return true
		}
	}

	return false
}

And finally that function is used before my switch statement in the Update function like this:

if isTableRebuildMessage(untypedMsg) {
		m.table = rebuildTable()
}

This makes sure my table is up to date before any other processing happens and before other messages like user input are sent to the table.