The Default derive macro adds : Default bounds to any generic parameters of the annotated type, even if they are not necessary for the generated implementation. To get the more general implementation, remove #[derive(Default)] and implement the trait manually.
The behavior of the derive macro is motivated by simplicity (avoiding doing any kind of analysis of the types of fields) and forward-compatibility (not making the bounds on the generated impl depend on private fields).
A useful technique for troubleshooting "funny" macro behaviour is to expand macros so you see what the compiler sees.
For simple examples, you can paste your Foo struct definition into the the playground and click Tools > Expand Macros. Otherwise check out the cargo-expand tool if you are wanting to expand macros in a larger crate.
Running it on Foo shows the compiler has added some prelude stuff at the top of the file...
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
... Then there is your code...
use std::collections::HashMap;
struct Foo<A, B> {
mapA: HashMap<A, B>,
mapB: HashMap<String, A>,
}
... And finally, we see the Default implementation generated by the compiler: