TDD works just fine with property-based tests, with each case representing an equivalence class. I like to randomly select from those classes because that eventually double-checks that I set my boundaries correctly. I often additionally pin the class boundaries in place.
My main gripe with it is the second-order concern that it encourages testing practices that are frankly not very intelligent.
How you should approach testing depends on what kind of function you are testing. Pure functions of their inputs should be tested with property-based tests. If you have
the whole rigmarole of "make a test that fails, then write the least amount of code that makes it pass" brings you to something like: and so on, where what you really want is to say something like: This obviously works less well when you have to deal with the real world, but even in that case TDD leaves you with a patchy and inflexible approach.