Types are not anti-modular: the culprit is module systems that don't allow type parameterization. Systems such as Java solve this problem for functions and constants by allowing code to be parameterized over interfaces. Bam, you can compile code using said functions and constants separately from their implementation.
The solution for types is exactly the same: move types into interfaces. Guess what, Objective Caml and Coq do this via module functors and it's glorious. If my airline scheduler module needs to compile separately from my graph module, well I can write:
module Scheduler(Graph: sig type graph val traverse: graph -> (string -> unit) -> unit end) = struct ...blabla... end
and I can compile that code without ever writing a snippet of the graph module -- not even defining the ADT!
TLDR: this problem has been solved 30 years ago by people who actually use typed languages.