Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I narrow a class's types to only functions accepting no arguments?

Playground example

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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"

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading