Files
2026-07-27 11:32:15 +02:00

1.2 KiB

Typestate Pattern in Go: Interfaces

Another way to implement the typestate pattern in Go is by using interfaces to restrict the methods available on an object based on its current state.

pwLocked := NewCredentialManager()
pwUnlocked, _ := pwLocked.Unlock("pssst")
pwUnlocked.Set("foo", "bar")
_, _ = pwUnlocked.Get("foo")
pwUnlocked.Lock()

In this implementation, both LockedCredentialManager and UnlockedCredentialManager are interfaces that are satisfied by a single internal credentialManager struct. The transitions return the same object but cast to the appropriate interface.

Caveats

Similar to the struct-based approach, interfaces in Go do not prevent the use of the original interface variable after a transition. Additionally, because the underlying type is the same, it's possible to cast the interface back to the original type or another interface if the underlying type is known, bypassing the state protections. It also still requires internal runtime checks to ensure consistency if the object is shared.

pwLocked := NewCredentialManager()
pwUnlocked, _ := pwLocked.Unlock("pssst")
pwUnlocked.(LockedCredentialManager).Unlock("psst") // This is possible and would cause a runtime error