I'm converting a large project from flow to TS and am having trouble figuring out how to create dynamic class methods. I threw together a simple working example of what I'm trying to do:
declare type logMethod = (msg: string) => void;
class Logger {
constructor(methods: string[]) {
methods.forEach(method => this[method] = (msg: string) => Logger.logMethod.call(this, method, msg))
}
static logMethod(method: string, msg: string) {}
[key: string]: any;
}
function LoggerFactory<T extends string>(methods: T[]): Logger & Record<T, logMethod> {
const logger = new Logger(methods);
return logger as Logger & Record<T, logMethod>;
}
const logger = LoggerFactory(['info', 'warn', 'error']);
logger.info('info');
logger.warn('warn');
logger.error('error');
this works just fine, as in info, warn, error, or any other method names I pass into the factory are typed properly. However I hate having extra JS just to make the type system happy. The LoggerFactory is completely unnecessary in JS and I'm trying to figure out how to get rid of it.
I was trying to go down a road like this:
class Logger<T extends string[]> {
[method in keyof T]: logMethod;
}
but that mapping syntax doesn't work on classes or interfaces, only normal types. Just looking for ideas here!
newtype syntax! With one minor tweak (playground), your first example is perfect! Though i realize it wasn't a requirement in my example, there are some other normal methods on the class. Also, I'm happy to addx=_xas normal JS!! I just didn't want entirely new functions, etc. If you want to answer I'll gladly accept, thanks!!!foo()bit to your example code, to motivate the intersection type.