> the amount of time I spent debugging types and signatures was really frustrating, and often left me googling the same error patterns to figure out where my mistake might be.

In my experience, people often describe their first experience with expressive static type systems in terms of "fighting with the compiler" (or similar phrasing). I think this is due to a poor introduction to static type systems, often in university settings.

A static type system has one purpose: to prevent you from running unsafe code. Every type error is just the compiler telling you "what you wrote isn't going to work". This isn't a fight; it's a conversation. You write some code, run the compiler, get back some errors, fix them, and run the compiler again. This process is repeated until your mental model of how the code should work is properly reflect in the code, as determined by the success of your compiler's type-checking.

There are frequently two sources of frustration in this process:

1. A difficult-to-use type system.

Some type systems are just obnoxious to use. (Older) Java required soooo much verbose typing. The resulting code would be difficult to read just because there was so much text on the screen. More modern Java is an improvement, but newer languages are often designed from the ground up to use type inference to alleviate your keyboard-typing obligation.

Another form of frustration is what you mention: inscrutable error messages. Haskell is pretty well known for having type errors that are not obvious to newcomers, and that turns the programmer-compiler conversation into a frustrating experience. Again, newer languages are making lots of progress here. I think Rust does a great job with its error messages, for example. Hopefully this is something the Haskell developers will look more into.

2. An insufficiently expressive type system.

If your type system is too limited, you'll have a hard time finding it particularly useful. If your types are "too big", they become unwieldy and unhelpful. Older languages frequently fared poorly in this metric, because "types" were meant primarily for memory optimization rather than programmer expressiveness. However, as our languages have become more user-centered, our type systems have become more expressive and, thus, easier to use to model data. Modern languages like Rust and Swift have taken a lot of inspiration from functional languages like Haskell and ML to provide type capabilities that are significantly more expressive than those in other languages.

I think type system inexpressiveness is a big part of why some people prefer dynamically typed languages, like Python. They find that they have a difficult time converting their mental model of the data into an explicit type, and so they move to an ecosystem where they simply don't have to deal with that. Personally, I think this indicates the need for better expressive type systems and better type system onboarding to teach people how to use them effectively, because if you rephrase the static type proposition to those programmers as "Would you like to guarantee that erroneous programs are simply never run?", I imagine most of them would enthusiastically shout "Yes!"