Explicit exceptions - a solution to fragile code dealing with exceptions

I previously talked about how simply "returning exceptions" isn't a great solution, because it doesn't self-document what exceptions are being returned when functions are simply propagating the exceptions down the call stack. I have recently realized that it doesn't have to be this way if you're using Typescript (Typescript isn't something I've had the opportunity to use much, but I would love to use it more - so excuse me if my Typescript example below isn't well-written).

With Typescript, one can declare what types of exceptions a specific function can return in each function signature, and Typescript can help make sure you handle all possible exceptions explicitly (usually). This sort of system certainly isn't perfect (and is probably a little verbose to use), but it is an improvement over what we've got today and might be enough for some people. Here's an example of how this might work:

// Exception utility class

class Exception <T> {
  constructor(public code: T) {}
}

// Example API

interface User {
  username: string,
}

// Notice how in the signature we explicitly declare each type of exception that can be returned.
// It gives this a similar feel to Java's checked exceptions, but without some of Java's issues.
function getUser(userId: number): User | Exception<'NOT_INITIALIZED' | 'NOT_FOUND'> {
  if (!initialized) return new Exception('NOT_INITIALIZED')
  const user = users.get(userId)
  if (!user) return new Exception('NOT_FOUND')
  return user
}