IME a lot of libraries that do duck-typing (for instance Python) make very little effort to explain what methods I'm supposed to implement or what the contract is supposed to be for those methods.
It also forces users of the API to explicitly state in code that they're intending to implement that interface, as opposed to just implementing a handful of seemingly random methods whose purpose will not be immediately clear to readers.
Also, AFAICT duck typing is incompatible with the approach taken in Rust or Haskell where the definition of a type can be decoupled from its implementation of various interfaces (called traits in Rust or type classes in Haskell), and where methods or attributes in different interfaces implemented for the same type can have the same name and not clash, because the object isn't the namespace for its methods. I strongly prefer this approach.