angular - Få tilgang til meta-annotasjon inne i klasse (TypeScript)


Når jeg merker en klasse med metadata i TypeScript, for eksempel for å lage en Angular2-komponent, kan jeg få tilgang til metadataene inne i den klassen?

import {Component} from 'angular2/core';

@Component({
    selector: 'app',
    templateUrl: '/app/components/app/app.component.html'
})
export class AppComponent {

    // can I access 'templateUrl' from above annotation here?

}

Svar #1

Med den nye Angular-versjonen bør du bruke det native Reflect-objektet. Ingen støtte for IE11, da:

const annotations = Reflect.getOwnPropertyDescriptor(MyModule, '__annotations__').value;

Les Jeff Fairleys svar nedenfor om hva du skal gjøre med dataene etter det

Du kan se en annotasjon/dekorator som et normalt funksjonskall. Til denne funksjonen blir 'Klasse/Funksjon'-objektet (ikke instans) sendt som første parameter, og parameterne (metadata) som andre argument.

Det avhenger imidlertid av implementeringen av den funksjonen hvis noe blir lagt til for eksempel i prototypen til klassen (dårlig praksis/eksponering av egenskap). TypeScript-kompilatoren og Angular2 gjør ting annerledes.

De bruker __decorate og __metadata-funksjonene, som genereres av TypeScript-kompilatoren. Dataene legges til med Object.defineProperty()-funksjonen. Pakken som er ansvarlig for dette er Reflect. (som under panseret bruker Object.defineProperty()-funksjonen i kombinasjon med en WeakMap).

Funksjonen Reflect.defineMetadata() brukes til å sette annotasjonene, og for å hente dem brukes den åpenbare Reflect.getMetadata().

Kort fortalt;

  • For å hente annotasjonene fra en klasse/komponent i Angular2, må du bruke:

    Reflect.getMetadata('annotations', ComponentClass); //@Component({}), @Pipe({}), ...
    
  • For å hente annotasjonene fra konstruktørparametrene i Angular2, må du bruke:

    Reflect.getMetadata('parameters', ComponentClass); //@Inject()
    
  • For å hente annotasjonene fra en egenskap i en klasse i Angular2, må du bruke:

    Reflect.getMetadata('propMetadata', ComponentClass); //@HostBinding(), @Input(), ...
    

Svar #2

@PierreDucs svar fungerer ikke for meg i Angular 5. Jeg gjorde litt mer lesing (beklager, jeg kan ikke finne alle de relevante lenkene å dele), og kom opp med følgende:

let decorator: Type<any>;
// you can cast the component class
decorator = (<any>AppComponent).__annotations__[0];
// or use with lodash.get
decorator = get(AppComponent, '__annotations__[0]');

//
// obviously, this is an array, and based on your app,
// you may have multiple decorators on one class, so iterate them
//


// if you want to just grab some data from the @Component:
const templateUrl: string = decorator.templateUrl;
// or from a @NgModule:
const declarations: Type<any>[] = decorator.declarations;


// or if you're trying to decide whether this is in fact a component:
if (decorator instanceof Component) {
  // do things
}
// or a provider
if (decorator instanceof Injectable) {
  // do different things
}
// or a module:
if (decorator instanceof NgModule) {
  // do things
}

// etc...

Jeg har ennå ikke oppgradert appen min til Angular 6, så jeg har ikke bekreftet at dette ikke har endret seg.

Relatert :

  • Her er en interessant artikkel om å lage en tilpasset dekoratør: https://blog.angularindepth.com/implementing-custom-component-decorator-in-angular-4d037d5a3f0d

Relaterte artikler