Description
Bug Report
π Search Terms
type guard assertion function intersection predicate
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about type guards
β― Playground Link
Playground link with relevant code
π» Code
type GuardIntersection = ((x: unknown) => x is number | string) &
((x: unknown) => x is number | boolean);
type AssertionIntersection = ((x: unknown) => asserts x is number | string) &
((x: unknown) => asserts x is number | boolean);
type GuardType = GuardIntersection extends (x: any) => x is infer U ? U : never;
// ^?
// type GuardType = number | boolean
type AssertionType = AssertionIntersection extends (x: any) => asserts x is infer U ? U : never;
// ^?
// type AssertionType = number | boolean
function example(guard: GuardIntersection, assertion: AssertionIntersection, x: unknown): number {
if (guard(x)) {
return x;
// ^?
// (parameter) x: string | number
}
assertion(x);
return x;
// ^?
// (parameter) x: string | number
}
π Actual behavior
When using infer
to extract the predicate type of the intersection of type guard function types, the predicate type of the last item in the intersection is inferred. (number | string
)
When calling a type guard function of the intersection type, the argument of the type guard function is narrowed to the predicate type of the first item in the intersection. (number | boolean
)
π Expected behavior
In both cases, I'd expect the inferred/narrowed type to be the intersection of the predicate types. (number
)
At the very least I'd expect the two types to be the same.
Aside: This is remarkably similar to the behavior of inferring the return type of function overload types (#26591). Coincidence?