Scan Decorated Classes in Typescript
1 min read

Scan Decorated Classes in Typescript

Scan Decorated Classes in Typescript

TL;DR: Make the decorator set a property in the class and look for it.

While trying my hand at writing an ORM, I had a problem of initialising the database through a dummy instantiation of some models, without running an explicit command. In java, I can use code generation to provide a list of objects following a pattern (e.g. implementing an interface). Here, the concepts are somewhat different and I found out I can use decorators.

My model looks like this:

import { table, field } from '../ngOrm/decorators'

@table({ name: 'LABELS', autoIncrement: true })
export class Tag {
  @field({ name: 'label', dbtype: 'TEXT', nullAllowed: false })
  label: string
}

where the @table() and @field are decorators.

Ideally, I should have a function along the lines:

function setup(): void {
    for(let obj in <list of objects decorated with @table>) {
        new obj();
    }
}

Now, obtaining the list is somewhat difficult since different classes can be in different files all over the place.

Solution

The solution I found is to have the decorator set an obscure property on the decorated object:

export function specialDecorator(item: any) {
  item.isSpeciallyDecorated = true
}

and add it to the @tabledecorator:

export function table(opts: TableOpts = {}): (target: Function) => void {
  specialDecorator(target) // <== here
  return (target: Function) => decorateClass(target, opts)
}

Once you have done this, the decorated model will have a property named isSpeciallyDecorated, which we can look for:

function scanScope(theScope: any) {
  for (let prop in theScope) {
    if (theScope[prop]['isSpeciallyDecorated']) {
      console.log(`Is ${prop} decorated?  ${theScope[prop]['isSpeciallyDecorated']}!`)
    } else {
      console.log(`${prop} is not specially decorated.  :-(`)
    }
  }
}

Now, all we have to do is invoke the function in the right place:

export { Photo } from './photo-model'
export { Tag } from './tag-model'

scanScope(this)

This will print out that our models are specially decorated.

Note: You need to explicitly import/export the models in your file as the call is only local (this is the current scope).