The term 'extends' can be interpreted as 'is assignable to'.
type F1 = (payload?: number) => null;
type Res2 = F1 extends (a: any) => any ? 1 : 2; // expected result is 1, but getting 2
Are (payload?: number) => null
and (a: any) => any
compatible? Let's delve into this:
// It works fine
const res2: (a: any) => any = (payload?: number) => null;
(a: any) => any
allows any value for a
, even if it's undefined or a number stated by payload. Hence, we confirm that (payload?: number) => null
is indeed assignable. Therefore, F1 extends (a: any) => any
should return true and yield 1.
Alternatively, you can make the function arguments optional using Partial, verifying if the resulting arguments are still assignable to the original ones:
type ArgumentType<F extends (...args: any) => any> = F extends (...args: infer A) => any ? A : never;
type FirstArgumentOptional<F extends (...args: any) => any> =
Partial<ArgumentType<F>> extends ArgumentType<F>
? true
: false
type T1 = FirstArgumentOptional<(a: any) => any>; // false
type T2 = FirstArgumentOptional<(a?: any) => any>; // true
type T3 = FirstArgumentOptional<() => any>; // true