Lots of frameworks and state management libraries already lean towards helpful design, in languages with async and ADTs as first-class citizens you've got a real leg up, but at the end of the day it comes down to preventing impossible states.
You can't have an error message when in the success state, you can't have success data while loading or waiting.
By preventing this at compiletime, it also means the UI can't ever show bogus data (i.e. it's impossible to have a success screen with the error message dangling at the bottom because somebody forgot to clear it)