typescript types: Second parameter must be of the type of method selected by the first, considering parameters and return of the selected method
11:12 11 Oct 2023

I would like to make a method that receives two parameters, methodName and method, the first should only accept names of methods that exist in the class itself, and the second method should only accept functions that receive the same parameters and have the same return as the method selected by the methodName parameter, below is my failed attempt:

type ClassMethodNames = {
  [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T];

class M {
  val!: string
  fnDat!: (str: string, num: number) => Date
  fnNum!: (num: number) => number
  fnStr!: (str: string) => string

  cheker<
    MethodName extends ClassMethodNames
  >(
    methodName: MethodName,
    method: this[MethodName]
  ) {
    console.log(methodName, method)
  }

  constructor() {
    // Should not produce type error
    this.cheker("fnDat", (str: string, num: number) => new Date)
    this.cheker("fnNum", (num: number) => num)
    this.cheker("fnStr", (str: string) => str)

    // Should produce type error
    this.cheker("val", () => { }) // methodNameError (val is not a method)
    this.cheker("fnDat", () => new Date) // argsError
    this.cheker("fnDat", (str: string, num: number) => null) // returnTypeError
    this.cheker("fnNum", (num: number) => "") // returnTypeError
    this.cheker("fnStr", (str: string) => 10) // returnTypeError
    this.cheker("fnNotExistsInM", () => { }) // methodNameError    
  }
}

//
const m = new M()

// Should not produce type error
m.cheker("fnDat", (str: string, num: number) => new Date)
m.cheker("fnNum", (num: number) => num)
m.cheker("fnStr", (str: string) => str)

// Should produce type error
m.cheker("val", () => { }) // methodNameError (val is not a method)
m.cheker("fnDat", () => new Date) // argsError
m.cheker("fnDat", (str: string, num: number) => null) // returnTypeError
m.cheker("fnNum", (num: number) => "") // returnTypeError
m.cheker("fnStr", (str: string) => 10) // returnTypeError
m.cheker("fnNotExistsInM", () => { }) // methodNameError

This current case has two problems, the first is that the method parameter does not consider the parameters of the received function, it only takes into account the return.

and it is not possible to use this method within the class itself.

typescript typescript-typings