Branding doesn't need to be weird and arbitrary, see Pythons NewType: https://docs.python.org/3/library/typing.html#typing.NewType
Reading TFA now, Pythons NewType seems to be equal to Haskells newtype. Yes, it's a hack for the type checker to work around existing language semantics and feels unergonomic at times when Parse, Don't Validate needs to fall back to plain validation, but I wouldn't call it neither weird nor arbitrary.
Python defaults uses nominal typing so isn't prone to this problem anyway.
The kind of "branding" I'm talking about is a hack only needed for structural typing systems. Consider something inspired by the C locale API, for example:
In a structural typing system, it is impossible to write a function that takes a union including more than one of `{NO_LOCALE, THREAD_LOCALE, GLOBAL_LOCALE, ENV_LOCALE}`, since they have no contents and thus cannot be distinguished. You have to hack around it, by some kind of casting and/or adding a member that's not actually present/useful at runtime.And this kind of need is quite common. So I maintain that structural typing is not a serious type system proposal.
(Then again, the man proponent for structural typing is TypeScript, which even in $CURRENTYEAR still lacks even a way to specify ubiquitous needs like "integer" or "valid array index").
I think a type system that permits a type (no_locale=()) | (thread_locale=()) | (global_locale=()) | (env_locale=()) would generally be considered structural. I think newtypes and structure field names are isomorphic in functionality. Where a nominal type system would use newtype(tag,X) a structural one could use struct{tag:X} (and this holds even if X is the unit/singleton type).