Haskell has a few libraries to do this. I particularly like unittyped[1], which not only keeps track of units but also converts among compatible ones automatically. So 1 meter + 1 inch would typecheck and be converted automatically, but 1 meter + 1 second would give you a type error.
The wiki page[2] has a bunch of examples, which I find pretty compelling. The one problem is that error messages are ugly, but they're ugly in a consistent way. You can just ignore the ugliness as unnecessary noise.
*Main> (1 meter / second) * 5 second
5.0 m/s⋅s
*Main> 2 meter + (1 meter / second) * 5 second
7.0 m
One cute thing is that prefixes like "kilo" are just functions, letting you write things like:
*Main> (42 kilo meter) `as` mile
26.097590073968025 mile
*Main> gallon `as` (cubic (deci meter))
4.546089999999999 dm⋅dm⋅dm⋅#
Haskell is really good at dealing with numeric types in general. For example, it's quite easy for a library to define its own types, which then behave just like built-in ones including nice syntax. Unittyped follows this philosophy, letting you use units with things that aren't floats, like rational numbers, meaning you don't have to lose precision.
*Main> (1 % 2) . meter `as` foot
625 % 381 ft
It's a really slick design and manages to give you safety
as well as additional expressivity (since units get converted automatically).
[1]: https://hackage.haskell.org/package/unittyped