Duck Typing always struck me as utterly absurd wishful thinking. Two different types built for the same task will almost certainly not happen to be API compatible.
There are cases where it can be useful. One thing that comes to mind is numerical code, where your algorithms are generic over things that have *,/,+,-,==,!=, conversion from 0 or 1 [or some subset thereof] do the "right thing". Trying to define proper interface types for what constitutes the "right thing" is somewhat tedious without much relative gain.
Yes, interfaces aren't just bags of data and methods. They have semantic meaning, too. An Employee, a Gun, and a ClayPot might all have a method named `fire()`, but they all mean different things. With structural typing, we can load our Employees into a Kiln and give HR a Gun to downsize the company, and nothing will stop us.
Its worked for us when dealing with local operations vs. cloud bucket operations. Protocols also help when you really don’t care to litter your code with some vendor specific object but instead just declare what functionality should be expected from the object passed in. It helps describe what you’re doing with it anyway, it’s why typing with Iterable can be helpful if you don’t care if it’s a list, set, or tuple.
I have bounced back and forth between typed and untyped languages in my two decades of employment history, and I prefer typed languages myself, even when I've been writing libraries nested deep in what I think the author would describe as the "infrastructure layer," but this is what I believe the original author of the linked piece is arguing.
No, in my experience you are trading off ease of coding for order of magnitude more production bugs.
So you do not write tests?
I absolutely do, and one of those effective tests is a simple type annotation.
In sequences, even just too calls like "more?" and "next" will let you entertain all kinds of strict and lazy possibilities.