Issue
I have the following code in Typescript (simplified)
interface TimeoutOption {
category: 'timeout'
time: number
}
interface UserOption {
category: Parameters<typeof addEventListener>[0]
}
type MyDelayOptions = Array<TimeoutOption | UserOption>
function delay(options: MyDelayOptions) {
for (const option of options) {
if (option.category === 'timeout') {
timeout = setTimeout(() => {
// not relevant
}, option.time) // need to cast and do (option as TimeoutOption) to not get an error
}
}
}
In order to avoid a compilation error I have to add the type assertion mentioned in the comment. For a human though it is clear that if the category is 'timeout' my option is of type TimeoutOption. How can I make this work without the type assertion? Complete refactors welcome.
Solution
The problem is that UserOption defines category as type string (indirectly, but that's what it comes out as). As a result, if (option.category === 'timeout') doesn't discriminate between your two union members, because UserOption could easily have category: "timeout" just like TimeoutOption does. The discriminant (category) has to clearly discriminate the union, but it doesn't in your case.
You could test for the presence of time instead (see *** below):
function delay(options: MyDelayOptions) {
for (const option of options) {
if ("time" in option) { // ***
const timeout = setTimeout(() => {
// not relevant
}, option.time) // need to cast and do (option as TimeoutOption) to not get an error
}
}
}
Answered By - T.J. Crowder
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.