Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't constrain function type using guard function

Tags:

typescript

I wrote the following type guard definition:

function is_zero_args<T, F extends (...args: any[]) => T>(func: F): func is () => T {
    return func.length === 0;
}

Logically, this should work - but TypeScript fails the compilation with the following error:

A type predicate's type must be assignable to its parameter's type.
  Type '() => T' is not assignable to type 'F'.
    '() => T' is assignable to the constraint of type 'F', but 'F' could be instantiated with a different subtype of constraint '(...args: any[]) => T'.

I know that F could be created with different args - that's what I'm guarding against.

like image 291
javajav Avatar asked Oct 24 '25 03:10

javajav


1 Answers

You don't need/want F to be a type parameter there. Callers are allowed to supply a specific type argument for F to which () => T may not be assignable (e.g. is_zero_args<string, (x: string) => string>(f)). The last line of your error message explains this ("F could be instantiated with a different subtype").

Here's another example of the same kind of error without involving function types:

function is_blah<S extends string>(str: S): str is 'blah' {
//                                                 ^^^^^^
// A type predicate's type must be assignable to its parameter's type.
//   Type 'string' is not assignable to type 'S'.
//     'string' is assignable to the constraint of type 'S', but 'S' could be instantiated with a different subtype of constraint 'string'.
    return str === 'blah';
}

Usually when a generic function's type parameter only has a single usage in the call signature you can remove that type parameter and instead inline its constraint. Indeed, that works here:

function is_zero_args<T>(func: (...args: any[]) => T): func is () => T {
    return func.length === 0;
}
like image 175
Matt Kantor Avatar answered Oct 25 '25 22:10

Matt Kantor



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!