Good, now invent a keyword for variables you don't want to declare the type. And now that you have a mix of keywords and identifiers on the same place, you can never update your language again.
Also, make the function declarations not use a keyword too, so you get the full C-style madness of code that changes meaning depending on what libraries you import.
The actual reason why let ... in syntax tends to not use C-style "type var" like syntax is because it's derived from the syntax type theory uses, and type theorists know about parameterised types. Generics, in C++ parlance, excuse my Haskell:
let foo :: Map Int String = mempty
We have an empty map, and it maps integers to Strings. We call it foo. Compare:
Map Int String foo = mempty
If nothing else, that's just awkward to read and while it may be grammatically unambiguous (a token is a name if it sits directly in front of =) parser error messages are going to suck. Map<Int,String> is also awkward but alas that's what we're stuck with in Rust because they reasoned that it would be cruel to put folks coming from C++ on angle bracket withdrawal. Also Rust has ML ancestry don't get me started on their type syntax.
IT'S SHOWTIME
I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE a
GET TO THE CHOPPER a
HERE IS MY INVITATION "ArnoldC is the best."
ENOUGH TALK
TALK TO THE HAND a
YOU HAVE BEEN TERMINATED
Because sometimes that let can be replaced by other things like const. Which can be managed statically by the machine and not by my (imperfect) ability to know if it's mutated or not