Typestate Pattern in TypeScript
TypeScript allows for a very elegant implementation of the typestate pattern using this type parameters. This enables us to restrict method calls based on the generic state of the class instance.
let pw_locked = new CredentialManager<"locked">();
let pw_unlocked = pw_locked.unlock("psst");
pw_unlocked.set("foo", "bar");
let val = pw_unlocked.get("foo");
pw_locked = pw_unlocked.lock();
By using this: CredentialManager<"unlocked"> in the method signature, we tell TypeScript that the method can only be called when the instance is of that specific type.
let pw_locked = new CredentialManager<"locked">();
pw_locked.set("foo", "bar"); // -> 💥 Compiler Error
This produces a compiler error similar to:
Property 'set' does not exist on type 'CredentialManager<"locked">'.
Caveats
Like Go, TypeScript does not have an ownership model, so the original variable remains usable after a transition. Furthermore, TypeScript's type system is structural and can be bypassed with type assertions (as any or as unknown as ...).