I didn't work much with static typed languages lately, so I'm really puzzled by your comment. If I expect an int in the age field of a JSON response and the server suddenly sends me a string, maybe with value "NaN", how do you check for that at compile time? I expect the program to either crash or manage the error at run time (try/catch, die-and-restart a-la-Erlang, etc)
Maybe JSON doesn't count as "statically typed API", but how many of them do common Internet services expose to the public? And how to we make sure that the server or any in between proxy doesn't misbehave and violates the contract?
Either way, you need to handle such failures, both in statically and in dynamically type-checked languages. The only difference is whether the handling happens explicitly throughout your code or automagically by an API that gives you back a well-behaved object. And both of these ways are possible in both static and dynamic languages (but static languages tend to go for the latter, whereas dynamic languages tend to make you do the former).
Does that make sense? I can show you some code if you’d like.
> It always seems to end up in types where every field is optional
“Always”? Not by a long shot. These situations where this is the case can be isolated and dealt with explicitly. You may object to the explicitness but — again, for reasons of robustness — proponents of static typing prefer this.