Identifiers belong to a domain. A userid belongs to a member of a set of Users, a groupid to Groups, and so on. You are happy to have a User object with a distinct type, and wouldn’t try to have a superset UserOrGroup class.
A string belongs to the domain of “all strings” and so the type system and compiler cannot catch something like “authorizeUser(id,…) where the id is in fact “” or a groupid or “null” or “undefined”.
Lots of code does what you describe. But I prefer to use the type system wherever I can.
Comments
Identifiers belong to a domain. A userid belongs to a member of a set of Users, a groupid to Groups, and so on. You are happy to have a User object with a distinct type, and wouldn’t try to have a superset UserOrGroup class.
A string belongs to the domain of “all strings” and so the type system and compiler cannot catch something like “authorizeUser(id,…) where the id is in fact “” or a groupid or “null” or “undefined”.
Lots of code does what you describe. But I prefer to use the type system wherever I can.