Home > front end >  typescript class constructor inferring types based on args of its function as argument
typescript class constructor inferring types based on args of its function as argument

Time:01-26

Sorry if the title is not very clear, but I don't know how to phrase my problem better.

I have a Process class:

class Process {
  readonly fn: Function;
  readonly parameters: any | any[]; // doing sth here to have the types inferred based on `fn` args
  nextMessage: Message | null;

  constructor(fn:Function, parameters: any|any[]){
    this.fn = fn;
    this.parameters = parameters;
  }
}

when instantiating a new Process Object:

function doTask(task: string){
  console.log(`doing ${task}`);
}
const message = new Process(doTask, "Something");

I want to have type check on the parameter that i pass to Message constructor to match the type on the function argument. like, in the code above, if I pass a number instead of string, I want to get an error.

CodePudding user response:

The simplest way is to have a type parameters that represents the parameter types of the function as a tuple:

class Process<T extends any[]> {
  readonly fn: (...args: T) => any;
  readonly parameters: T; // doing sth here to have the types inferred based on `fn` args
  
  constructor(fn: (...args: T) => any, parameters: T){
    this.fn = fn;
    this.parameters = parameters;
  }
}

function doTask(task: string){
  console.log(`doing ${task}`);
}
const message = new Process(doTask, ["Something"]);

Playground Link

CodePudding user response:

For this purpose you have the type Parameters:

class Process<F extends Function> {
  readonly fn: F;
  readonly parameters: any | any[]; // doing sth here to have the types inferred based on `fn` args
  nextMessage: Message | null;

  constructor(fn: F, parameters: Parameters<F["apply"]>) {
    this.fn = fn;
    this.parameters = parameters;
  }
}

It does exactly what you would expect, extracting the parameter types.

It's implemented like this:

/**
 * Obtain the parameters of a function type in a tuple
 */
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
  • Related