There is always a necessary distinction between specification and implementation: if there weren't, one of them would have no value. We often suggest that the intent of a piece of code should be specified in comments, and this is in that category. This way, the compiler can read your comment and figure out if it needs updating! Languages without dependent types work this way too - but you have to try very hard indeed to be eloquent in type signatures, and being able to talk about values lets you say a bit more.
Coming onto your second point: if the function is only valid for some set of values of the given type, why is it 'not really called for' to create specialised types for it? If you call it with something else and it runs, it will be a bug. Newtypes or wrappers are common patterns.
I think that most mainstream typed languages have common constructs to offer that 'A or a B' value you want: this is solved via inheritance, `Either`, `Result`, or `std::variant`.