In my handleChange
method I’ve tried to combine checkbox with other input/select elements:
handleChange = (
event:
| ChangeEvent<HTMLTextAreaElement>
| ChangeEvent<HTMLInputElement>
| ChangeEvent<HTMLSelectElement>
) => {
this.setState({
[event.target.name]:
event.target.type == "checkbox"?
event.target.checked:event.target.value,
} as unknown as Pick<IFormState, keyof IFormState>);
};
But encountered with this error: Property 'checked' does not exist on type '(EventTarget & HTMLTextAreaElement) | (EventTarget & HTMLInputElement) | (EventTarget & HTMLSelectElement)'. Property 'checked' does not exist on type 'EventTarget & HTMLTextAreaElement'.ts(2339)
Why it’s combine two entities, like EventTarget & HTMLTextAreaElement and if it possible to resolve it here?
Now I have separate handler for checkbox which is working properly:
handleCheckboxChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({
[event.target.name]: event.target.checked,
} as unknown as Pick<IFormState, keyof IFormState>);
};
2
Answers
I've just implemented type assertion principle here for
event.target as HTMLInputElement
:This is because the property
type
does not discriminate between the different HTMLElement types: you know that the value oftype
for checkbox elements is"checkbox"
at runtime, but at compile time – or writing time if you prefer – the compiler doesn’t know anything about that.So, when trying to access the
checked
property, the compiler assumes that it must be present in every type of the union that can be passed to the method. And don’t find it in two of them.It all comes down to the way the various HTMLElement types have been written. If you look at them, you’ll see that they don’t declare the property
type
in a way that allows the compiler to discriminate between them:type
is of typestring
.Would it have been written this way, it would allow the compiler to discriminate:
And of course, ideally, there should be a type for the checkbox element, establishing that the type is
"checkbox"
:But this type doesn’t exist, at least in the official type declaration that my IDE depends on.
Anyway, the behaviour that you encounter is perfectly normal. I recommend that you write your own discriminated types to overcome this issue – it is easy and actually kinda fun.
EDIT: Something like that: