Use a method type while still inferring arguments

Viewed 48

Use Case

I have a class that is constructed by passing in a list of methods and then lets you call those methods through the class (the class adds some additional functionality). These methods have the class (Foo) bound as their context when being called. So I have a FooMethod type.

class Foo {
  public constructor(methods) {}
}

const myMethod: FooMethod<number> = function(value: number): number {
  return value
}

const myMethods = [myMethod]

const foo = new Foo(myMethods)

type FooMethod<T> = (this: typeof foo, ...args: any[]) => T

type MyMethodParameters = Parameters<typeof myMethod> // any[]

Issue

By adding the type FooMethod<number> to the myMethod const. I can no longer get the type of the arguments for the function by doing Parameters<typeof myMethod>

Question

Is there a way to have the FooMethod type still infer the arguments? I'd like to be able to do Parameters<typeof myMethod> and still get [number]

1 Answers

This is because in your type FooMethod<T> you declare the rest parameter as being any[].

You could add the arguments as a generic to your type:

type FooMethodNew<Args extends any[], ReturnValue> = (this: typeof foo, ...args: Args) => ReturnValue

But may be redundant/verbose in practice

const myMethodNew: FooMethodNew<[value: number], number> = function(value: number): number {...}

Instead, you can use a helper function to help leverage the inferencing powers of functions

const fooMethodBuilder = <Args extends any[], ReturnValue>(func: FooMethodNew<Args, ReturnValue>) {
    return func
}

const myMethodBuilt = fooMethodBuilder(function(value: number): number {
    console.log(this)
    return value
})

type MyMethodParameters3 = Parameters<typeof myMethodBuilt> // [value: number]

View this on TS Playground

Related