Reputation: 205
I have following class:
const LOG_LEVELS = ['error', 'warn', 'info', 'debug'];
class Logger {
log (level, message) {
// some code for logging
}
}
for (const LEVEL of LOG_LEVELS) {
Logger.prototype[LEVEL] = function(message) {
this.log(LEVEL, message);
}
}
I want to type hint above code with typescript.
I have tried the following:
const LOG_LEVELS = ['error', 'warn', 'info', 'debug'];
class Logger {
public [key in LOG_LEVELS]: (message: string) => void;
public log (level: string, message: string): void {
// some code for logging
}
}
for (const LEVEL of LOG_LEVELS) {
Logger.prototype[LEVEL] = function (message: string): void {
this.log(LEVEL, message);
};
}
But I got "A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type" inside class definition and "Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Logger'" on the prototype extension.
What is the correct way to type hint dynamically added class methods? Is it possible to achieve type hint without defining all the log level methods explicitly?
I'm using typescript 3.5.3.
Upvotes: 1
Views: 119
Reputation: 249666
You can use interface/class merging to merge a mapped type into the class. If we use as const
in the log levels we get all the methods as expected:
const LOG_LEVELS = ['error', 'warn', 'info', 'debug'] as const;
interface Logger extends Record<typeof LOG_LEVELS[number], (message: string) => void> {}
class Logger {
public log (level: string, message: string): void {
// some code for logging
}
}
for (const LEVEL of LOG_LEVELS) {
Logger.prototype[LEVEL] = function (message: string): void {
this.log(LEVEL, message);
};
}
new Logger().error("") // ok
Upvotes: 1