Not really your question--others have provided examples of type systems as macros--but they can't, they can only do local rewrites. You couldn't, for example, express mutation or non-local control flow if you didn't have them already; On the expressive power of programming languages [0] is rather theoretical but does set out the boundary of what macros can and can't do. That they're local means everyone has to buy into your type system if you want it to be a macro, though.
[0] https://www.sciencedirect.com/science/article/pii/0167642391... though https://www.youtube.com/watch?v=43XaZEn2aLc might be a useful walkthrough of the ideas being presented
lexilambda created Typed Racket on top of Racket. https://github.com/racket/typed-racket
Turnstile relies on the fact that in Racket, you can have identifier macros [1] which can be expanded in pretty much any location (except binding, naturally). Racket is unique in this regard. Clojure has a mechanism to get roughly the same thing, but it's complicated. [2]
1: https://docs.racket-lang.org/guide/pattern-macros.html#%28pa...
2: https://lambdaland.org/files/2024_ecoop_type_tailoring.pdf