typescriptnestjstypeormtypedi

how to implement an abstract class with static properties in typescript


I am creating a job system and I want my DSL to look like the following:

@ScheduledTaskProcessor()
export class ScoringProcessor extends AbstractScheduledProcessor<ScoringInput> {

  static cron = CRON_NIGHTLY_FIRST_BATCH

  async process(args: ScoringInput) {
     // does some work
  }
}

i would love AbstractScheduledProcessor to look like the following:

export abstract class AbstractScheduledProcessor<T> {

  abstract static cron: string;

  abstract process(args: T): Promise<void>

  ... other non abstract method follow ...

but i get: TS1243: 'static' modifier cannot be used with 'abstract' modifier.

Can anyone suggest a path forward. Perhaps I can use my class decorator as a HOF to create the class with the static property.

FYI my ScheduledTaskProcessor decorator function curently looks like this:

import { Container } from 'typedi'


export function ScheduledTaskProcessor(): ClassDecorator {

  return function(target) {
    console.log('registering: ', target)
    Container.of('ScheduledTaskProcessor').set(target.name, target)
  }

}

Solution

  • You can make sure that you have to set a static value with decorators. The approach would look like this:

    // This interface represents the type of an uninstantiated class, so the class itself.
    // In Javascript it's just regularly called constructor but you could also call 
    // it SchedulerClass
    interface SchedulerConstructor { 
      cron: string; // A member of the uninstantiated class/constructor is static.
      new (...args: any[]): any;
    }
    
    // Decorators get the class itself passed not an instantiation of it. This means interfaces
    // we set here define the structure of the class and not of the object. This gives us
    // the opportunity to use our constructor-interface to restrict which classes can be
    // decorated and thus enforcing the static member cron.
    export function ScheduledTaskProcessor(constructor: SchedulerConstructor) {
        // decorator logic
    }
    
    @ScheduledTaskProcessor // No compiler warning because the static is set.
    class ScoringProcess {
        static cron = "test"
    }
    
    @ScheduledTaskProcessor // Error static cron not declared.
    class ScoringProcessError {
    }
    

    Playground