This should solve the immediate problem with negative numbers.
However, I gave this some though and realised that there is still a problem with large numbers. For example:
(cl-typecase (+ (max-char) 1)
(character "A character")
(fixnum "A fixnum")
(t "Something else"))
Returns "A character".
However, "(format "%c" (+ (max-char) 1))" raises the error "(wrong-type-argument characterp 4194304)".
The question is if `cl-typecase', `format', and `characterp' should have the same definition on what a character is. If not, then ERT must be modified to handle this, e.g. by using `base-char' rather than `character'.
Personally, I would perfer if `character' would mean the same thing in all contexts. I would suggest that we restore the old meaning of `character', drop `base-char', and add a new type class, say `key-event', that could include things like ?\M-\C-x.