Haskell error messages are far less verbose, but I find them hard to read. What makes it worse is that often the error message involves a lot of deeply nested types that were hidden from me before by library writers using an alias. So I’ve had a lot of “where did that come from?” moments.
I had this problem when being onboarded into a TypeScript codebase recently. Unfortunately I don't think there's a technical solution to it: the type system simply won't stop you from making types that are way too complicated (unless you use a language like Go where the type system is intentionally lobotomized, which obviously comes with its own problems).
We're used to avoiding complexity when it comes to logic, but maybe there's less awareness when it comes to types. Maybe what we need is to have a bigger conversation around that so people realize it's something that needs to be on their radar.
The thing is, these types aren't usually complex in the way that logic is. Complex logic generally means lots of loops and conditions and such, maybe shared mutable state. Linear code that just calls a series of independent functions one after another is not generally considered complex, even though it may ultimately result in the execution of lots of code. What generally leads to these confusing errors is just simple types composed end-to-end. The problem is that while compilers are good at picking out the specific part of a function that's causing problems, they generally can't do the same thing with types, so it's kind of like if every time you got an exception, the entire module source was pinpointed as the problem.
Type systems are really good for detecting contradictions; they're much less good at figuring out which piece should be different. For any given type error, there may be half a dozen different changes to the code that would resolve it in different ways. Type systems often have no real way of guessing the user-intent there. There are loose heuristics, like... an explicit return type is more likely to be intentional (and therefore correct) than the type of the local value that's being returned. But I'm not aware of any formalism around this "ranking" of which types are most likely to be unintentional. Maybe we need one.
The only immediate solution I can see is to keep types simple enough that the user can fit the entire relevant type-space in their head (and in the IDE dialog!), so that they themselves can determine which part is actually "wrong" (as opposed to just contradictory).