Empty is not the same as "no value".
HTMLInputElement.value is '' when you have an invalid entry. If .value is not '', then it's not empty. That's definite, but since there are times when .value === '' but not empty, we need to test. For example, in Chrome, with a number input type, if you type . or e it will be placed in the input box, but .value will not change from '' because it's invalid.
<input type=number>
We can ask the browser for more information and thankfully ValidityState is extremely well supported. Basically, if there's no value, but the browser says there's a bad input, then it's not empty.
function isInputEmpty(input) {
  return !input.value && !input.validity.badInput;
}
Edit: Credits to @osullic for find this in spec:
A control's value is its internal state. As such, it might not match the user's current input.
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#a-form-control's-value