Let's say I have this class:
class Nandar {
stuff: string | null = null;
doSomething(a: string, b: string): void {
console.log(`${a},${b}`);
}
nothing(): void {
console.log('nothing');
}
}
I can use this type to extract the class's properties, narrowing the keys to only a given function signature:
type Delegates<Type, Fn> = keyof {
[K in keyof Type
as Fn extends Type[K] ? K : never]: K
};
For example:
type StringDelegate = (a: string, b: string) => void;
const delegate: Delegates<Nandar, StringDelegate>; // delegate's only possible value is 'doSomething'
If I want to narrow to Nandar.nothing
's type, though, I have a problem.
Using similar code:
type NothingDelegate = () => void;
const delegate: Delegates<Nandar, NothingDelegate>; // delegate's values can be 'doSomething' or 'nothing'
I don't want 'doSomething'; I want 'nothing' only. Basically Typescript takes () => void
to refer to any function, using any number of arguments and any return type. That's not what I want Typescript to do: I want it to refer to functions using no arguments and returning nothing.
The handbook says that
a void-returning callback type says "I'm not going to look at your return value, if one exists"
But I DO want to look at the return value, and ensure that it is void
. I also want to ensure that the function has no arguments. Is there syntax for that?
CodePudding user response:
The problem is that for a function to be assignable to another, it doesn't necessarily need the same arity. If a function's parameter types matches another function's, and the only difference is that the function takes less parameters, then it is assignable:
type UhOh = (() => void) extends ((a: string, b: string) => void) ? true : false;
// ^? true
Here you can see that a function that takes no arguments is assignable to a function that takes two arguments. To make sure that the function has no arguments, you may use the Parameters utility type to check that it has no parameters:
type NoArgFns<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? Parameters<T[K]>["length"] extends 0 ? K : never : never
}[keyof T];
type T = NoArgFns<Nandar>;
// ^? "nothing"