The catch is that you have to define way more types, but if the code is complex enough it's really worth it.
I think educating the developer / team on the existing codebase first would be the right step. Spend a day just going through the code. Learn how it connects, learn the full scope of the project. After this, make your changes in a way that fit into the existing code.
I've had too many offshore developers re-imnplement existing functionality, like reading data from an excel spreadsheet, simply because they did not look through the code that was already there. It cost them 2 hours of work to add another library and implement it, when the code they already needed was a simple using statement away.
In theory, this is why good orgs have senior devs: they know the codebases already. Furthermore, they should be reviewing these changesets to call out devs who mis-document or scatter about the code. But senior devs are people too, and they miss things. Additionally, some codebases are enormously complex, and it's virtually impossible for a single dev to understand it completely.
So I moved towards descriptive variable and function names, but those could lie as well.
So I'm thinking, how could we ensure truthful intentions at all?
And I think only a combination of small pull requests, good variable and function names and a thorough review can save us here.
But I don't know, I'm just a junior developer.