Indeed, and I would further argue that business data be dynamically typed, because business data is often messy and changeable, whereas the plumbing that carries it can be statically typed to ensure you are connecting the pipes correctly.
Static typing easily leads to a over-specification of types.
With dynamic typing the least specific type that will make this work is automatically implied. You can often make huge changes to the underlying data structures and things will just work.
Basically: I need a Car Object with these exact fields vs give me a thing with the field "foobar" that contains something that I can concatenate with another things.
(Though static languages with structural typing like TS muddle the water here as they can represent some of the power of dynamic languages. That might be part of why TS is so popular. The problem is that types in dynamic languages can easily get super complex without feeling complex while for static languages you might need very advanced features (dependent types and other scary stuff) to represent some cases.)
The big downsides when working with dynamic languages: You need to have tests or at least some reliable way to test you program. If not, refactoring can be indeed worse than what you know from static languages.
Also static types make it easier to safely make changes to a program without actually understanding most of the code as you can just follow compiler errors while dynamic languages require you to have some model of what is going on in your head. So for people that jump projects a lot, static typing also allows for easier refactoring while dynamic typing allows for more productivity when one is more intimate with the code.
> Basically: I need a Car Object with these exact fields vs give me a thing with the field "foobar" that contains something that I can concatenate with another things.
Um, that's another matter entirely. Polymorphism. Mainstream statically typed programming languages until recently knew exactly one type of polymorphism based on objects, classes and interfaces. It is object-level polymorphism that lies at hear of OOP.
This form of polymorphism is easy to implement in compiler or interpreter, but it also is very limited in expressiveness. So proper functional languages use parametric object-level and function-level polymorphism and allow dictionary passing (both implicit and explicit). This approach filters into mainstream programming language: generics in Java, templates in C++ and so on.
The point is, Polymorphism in dynamic languages is pretty trivial.
There is a reason the golang devs resisted introducing generics for so long, it introduces complexity and can be hard to debug.
If you read my side-note:
> The problem is that types in dynamic languages can easily get super complex without feeling complex while for static languages you might need very advanced features (dependent types and other scary stuff) to represent some cases
If you want to have a functional example: Elm and it's lack of type classes or similar features. There is a reason Elm is resisting to implement a better way to add ad hoc polymorphism for better or worse. It is difficult to fit into the goal of Elm being a simple and easy to use language.
So yes, you can either have a more complex static type system and pay the price for that or just bite the bullet and over specify types.(The problem is also one of ergonomics. Programmer might over specify types because that is the path of least resistance or because things like generics make code harder to debug.)