After studying the method outlined in this post, I successfully created an Or
function that accepts a series of type guards and outputs a type guard for the union type. For example: x is A + x is B => x is A | B
. However, I encountered difficulties using the resulting function as an argument in Array.filter
.
Definitions:
type TypeGuard<A, B extends A> = (a: A) => a is B;
type GuardType<T> = T extends (o: any) => o is infer U ? U : never
class A { q: any }
class B { p: any }
declare function isA(x: any): x is A
declare function isB(x: any): x is B
function Or<T extends TypeGuard<any, any>>(guards: T[]): T extends TypeGuard<infer A, any> ? (a: A) => a is GuardType<T> : never;
function Or<T extends TypeGuard<any, any>>(guards: T[]) {
return function (arg: T) {
return guards.some(function (predicate) {
predicate(arg);
});
}
}
Code example:
let isAOrB = Or([isA, isB]); // inferred as ((a: any) => a is A) | ((a: any) => a is B)
let isOr_value = isAOrB({ q: 'a' }); // here isAOrB is inferred as (a: any) => a is A | B which is what I want
[{}].filter(isAOrB).forEach(x => { }); // here I expected x's type to be inferred as A | B because of the type guard, however filter's overload is the regular one, returning the same {}[] type as the source array
To avoid writing a lambda expression as the argument for filter
in order to force type inference, I seek an alternative solution.
[{}].filter((x): x is A | B => isAOrB(x)).forEach(x => { });
Unfortunately, this workaround is not ideal for my requirements.
The same problem with an And function combining type guards
Utilizing the UnionToIntersection
construct highlighted in this answer, I attempted to correctly type the And
function but encountered the following error:
function And<T extends TypeGuard<any, any>>(guards: T[]): T extends TypeGuard<infer A, any> ? (a: A) => a is UnionToIntersection<GuardType<T>> : never;
// the above gives error A type predicate's type must be assignable to its parameter's type.
Type 'UnionToIntersection<GuardType<T>>' is not assignable to type 'A'.
Type 'unknown' is not assignable to type 'A'.