Nick Bull
Nick Bull

Reputation: 9846

Infer argument type based on a prior argument's generic type

I have a generic type defined as follows:

export type LogBuilder<
  T extends Logger<U>,
  U extends LoggerOptions
> = (options: U) => T;

I can use this as follows:

interface WinstonLogger extends Logger<WinstonOptions> {
  // Object.keys(Winston.config.syslog.levels)
  emerg: Log;
  alert: Log;
  crit: Log;
  error: Log;
  warning: Log;
  notice: Log;
  info: Log;
  debug: Log;
}

const declareWinstonLogger: LogBuilder<WinstonLogger, WinstonOptions> = (options) => {
  return ...;
}

Notice that the WinstonLogger extends with a generic type WinstonOptions.

Is there a way in LogBuilder to infer U from the generic type T<U>, so that I don't need to specify the second type in LogBuilder<WinstonLogger, WinstonOptions>?


I know I can define LogBuilder to have a default value of LoggerOptions for U:

export type LogBuilder<
  T extends Logger<U>,
  U extends LoggerOptions = LoggerOptions
> = (options: U) => T;

and I know Typescript has an infer keyword, which I attempted unsuccessfully to solve this problem. I'm hoping there's some way to combine these to drop the need to declare the second type generic in LogBuilder, and have that default to WinstonOptions, and having the above LogBuilder definition has it default to LoggerOptions - is that possible?

Upvotes: 0

Views: 39

Answers (1)

Tobias S.
Tobias S.

Reputation: 23825

The infer keyword should work here.

export type LogBuilder<
  T extends Logger<any>,
> = (options: T extends Logger<infer U> ? U : never) => T;

We can extract the type U from Logger in a conditional type for the options parameter.

Upvotes: 1

Related Questions