angulartypescriptangular2-templatetransclusion

Type checking components


I want to pass a component class as input to another component:

@Component({selector: 'dummy-comp', template:'i am dummy'});
class Dummy {}

@Component({
  selector: 'not-so-dummy',
  template:'<ng-content *ngComponentOutlet="transcluded"></ng-content>'
})
class LessDummy {
  @Input() transcluded: ???
}

What type should I use for transcluded? Dummy doesn't extend anything, instead it is using the @Component decorator. On the other hand there is a Component type, that extends from Directive... Here is some added testing:

let dummy = Dummy, component = Component;
typeof dummy // "function"
dummy.name // "Dummy"
typeof component // "function"
component.name // "DecoratorFactory"
dummy instanceof component // false

If I understand correctly I can use Function as type for my transcluded input but ideally I'd like to narrow it down. Perhaps I'm going about this the wrong way but here is what I'm trying to achieve:

<div [ngSwitch]="getTypeOf(input)">
  <div *ngSwitchCase="'Component?'">
    <ng-content *ngComponentOutlet="input"></ng-content>
  </div>
  <span *ngSwitchCase="'string'">{{input}}</span>
  <span *ngSwitchCase="'function'">{{input()}}</span>
</div>

I'm at a total loss as to what logic to put it my getTypeOf function.

edit: according to this website:

The prototype of the original constructor is copied to the prototype of f to ensure that the instanceof operator works as expected when we create a new instance of Person.

That would explain why instanceof doesn't work.

edit2: some luck with Reflect:

 Reflect.getMetadata('annotations',dummy)[0].selector // "dummy-comp"

Solution

  • Looks like this is working:

    private getTypeOf(d:any): string {
      let type:string = typeof d;
      if (type === 'function') {
        let metaKeys:string = Reflect.getMetadataKeys(d);
        if (metaKeys.indexOf('annotations') > 0) {
          let annotations:string[] = Reflect.getMetadata('annotations', d);
          if (annotations.indexOf('@Component') > 0) {
            type = '@Component';
          }
        }
      }
      return type;
    }
    

    For more details looks at the Reflect documentation.

    Note that doesn't work on Internet Explorer.

    edit the metadata methods documentation mysterioudly disappeared from MDN website overnight, you can have a look at this website instead