Reputation: 53
I am reading the book Programming TypeScript. I am confused by the refinement illustrated by the following example:
type UserTextEvent = { value: string; target: HTMLInputElement };
type UserMouseEvent = { value: [number, number]; target: HTMLElement };
type UserEvent = UserTextEvent | UserMouseEvent;
function handle(event: UserEvent) {
if (typeof event.value === "string") {
event.value; // string
event.target; // HTMLInputElement | HTMLElement (1)
// ...
return;
}
event.value; // [number, number]
event.target; // HTMLInputElement | HTMLElement (2)
}
I think the type of event.target in (1) and (2) should be HTMLInputElement and HTMLElement respectively. My understanding is that the type of event.target is definite if the type of event.value is definite. But it is HTMLInputElement | HTMLElement instead. Can someone explain it more clearly than the book? Thanks.
Upvotes: 2
Views: 213
Reputation: 2939
You are only checking the type of the property unfortunately typescript will not assume the class type because of that. To do that you have to check that yourself with a method that infers the type.
type UserTextEvent = { value: string; target: HTMLInputElement };
type UserMouseEvent = { value: [number, number]; target: HTMLElement };
type UserEvent = UserTextEvent | UserMouseEvent;
function isUserTextEvent(event: UserEvent): event is UserTextEvent {
return typeof event.value === "string";
}
function handle(event: UserEvent) {
if (isUserTextEvent(event)) {
event.value; // string
event.target; // HTMLInputElement (1)
// ...
return;
}
event.value; // [number, number]
event.target; // HTMLElement (2)
}
You can check here on the playground
when you verify
typeof event.value === "string"
Typescript can only infer that value is in fact a string and in the else can only be the [number, number]
But it cannot infer that value
is HTMLInputElement
or HTMLElement
, so still considers HTMLInputElement | HTMLElement
. You need to use a method to say that in fact event is UserTextEvent
Upvotes: 1