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
