TypeScript seems to have problems to infer union types of type guards. As an example, consider a function to combine an array of type guards with the following signature
function combine<T>(guards: ((x: any) => x is T)[]): (x: any) => x is T
and consider the following type guards with A
and B
having different properties
function isA(x: any): x is A
function isB(x: any): x is B
Now I would expect combine([isA, isB])
to work and have the inferred type (x: any) => x is A | B
but instead I get an error saying that an argument of type((x: any) => x is A | (x: any) => x is B)[]
is not assignable to parameter of type (x: any) => x is A
, meaning that T
is inferred as A
rather than A | B
.
When specifying T
explicitely, i.e. combine<A|B>([isA, isB])
, it works as expected. Is there a way to change the signature of combine
such that this could be inferred?
You can use a type parameter to denote the whole function instead of just the guarded type. This allows the compiler to infer a union of guard functions. We can then use a conditional type to extract the union of guarded types :
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
declare function combine<T extends ((x: any) => x is any)>(guards: T[]): (x: any) => x is GuardType<T>
let isAB = combine([isA, isB]); // (x:any) => x is A|B
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With