interface ClassDecoratorDescriptor < TFunc extends Function > {
target : TFunc ;
// TypeScript specific
type ?: Function ;
paramTypes ?: Function [ ] ;
returnType ?: Function ;
}
interface ParameterDecoratorDescriptor < TFunc extends Function > {
target : TFunc ;
paramIndex : number ;
// TypeScript specific
type ?: Function ;
paramTypes ?: Function [ ] ;
returnType ?: Function ;
}
interface MemberDecoratorDescriptor < T > {
target : Object ;
propertyKey : string | symbol ;
descriptor : TypedPropertyDescriptor < T > ;
// TypeScript specific
type ?: Function ;
paramTypes ?: Function [ ] ;
returnType ?: Function ;
}
interface TypedPropertyDescriptor < T > {
enumerable ?: boolean ;
writable ?: boolean ;
configurable ?: boolean ;
get ?: ( ) => T ;
set ?: ( value : T ) => void ;
value ?: T ;
}
type DecoratorFunction = < TFunc extends Function > ( desc : ClassDecoratorDescriptor < TFunc > ) : TFunc | void ;
type ParameterDecoratorFunction = < TFunc extends Function > ( desc : ParameterDecoratorDescriptor < TFunc > ) : TFunc | void ;
type MemberDecoratorFunction = < T > ( desc : MemberDecoratorDescriptor < T > ) : TypedPropertyDescriptor < T > | void ;
class Person {
@nonenumerable
get kidCount ( ) { return this . children . length ; }
}
function nonenumerable < T > ( { target, propertyKey, descriptor } : MemberDecoratorDescriptor < T > ) : void {
descriptor . enumerable = false ;
}
class Person {
@memoize
get name ( ) : string { return `${ this . first } ${ this . last } ` ; }
set name ( value : string ) {
let [ first , last ] = value . split ( ' ' ) ;
this . first = first ;
this . last = last ;
}
}
function memoize < T > ( { target, propertyKey, descriptor } : MemberDecoratorDescriptor < T > ) : void {
let getter = descriptor . get , setter = descriptor . set ;
descriptor . get = function ( ) : T {
let table = memoizationFor ( this ) ;
if ( propertyKey in table ) { return table [ propertyKey ] ; }
return table [ propertyKey ] = getter . call ( this ) ;
}
descriptor . set = function ( value : T ) {
let table = memoizationFor ( this ) ;
setter . call ( this , val ) ;
table [ propertyKey ] = val ;
}
}
let memoized = new WeakMap < any , any > ( ) ;
function memoizationFor ( obj : any ) : { [ key : string | symbol ] : any ; } {
let table = memoized . get ( obj ) ;
if ( ! table ) {
table = Object . create ( null ) ;
memoized . set ( obj , table ) ;
}
return table ;
}
// A simple decorator
@annotation
class MyClass { }
function annotation ( { target } : ClassDecoratorDescriptor < Function > ) : void {
target . annotated = true ;
}
@inject (dependency injection marker)
interface Class < T > extends Function {
new ( ...args : any [ ] ) : T ;
prototype : T ;
}
class CompositionContainer {
private _instances = new Map < Class < any > , any > ( ) ;
private _typeRegistry = new Map < Class < any > , Class < any > > ( ) ;
public for < T > ( baseType : Class < T > ) {
return {
use : ( concreteType : Class < T > ) : void {
this . _typeRegistry . set ( baseType , concreteType ) ;
}
} ;
}
public get < T > ( type : Class < T > ) : T {
var instance = this . _instances . get ( type ) ;
if ( ! instance ) {
type = this . _typeRegistry . get ( type ) || type ;
var parameters = constructorRegistry . get ( type ) ;
var args = parameters ? parameters . map ( paramType => this . get ( paramType ) ) : [ ] ;
instance = Reflect . construct ( type , args ) ;
this . _instances . set ( type , instance ) ;
var properties = propertyRegistry . get ( type ) ;
if ( properties ) {
for ( var [ propertyKey , type ] of properties ) {
Reflect . set ( instance , propertyKey , this . get ( type ) ) ;
}
}
}
return instance ;
}
}
let propertyRegistry = new Map < Class < any > , Map < string | symbol , Class < any > > > ( ) ;
let constructorRegistry = new Map < Class < any > , Class < any > [ ] > ( ) ;
function inject ( { target, propertyKey, paramIndex, type, paramTypes } ) : void {
if ( typeof propertyKey === "string" || typeof propertyKey === "symbol" ) {
// @inject on property
var properties = propertyRegistry . get ( target ) ;
if ( ! properties ) {
properties = new Map < string | symbol , Class < any > > ( ) ;
propertyRegistry . set ( target , properties ) ;
}
properties . set ( propertyKey , type ) ;
}
else if ( typeof paramIndex === "number" ) {
// @inject in parameter
var parameters = constructorRegistry . get ( target ) ;
if ( ! parameters ) {
parameters = new Array < Function > ( target . length ) ;
constructorRegistry . set ( target , parameters ) ;
}
parameters [ paramIndex ] = type ;
}
else if ( typeof target === "function" ) {
// @inject on constructor
var parameters = constructorRegistry . get ( target ) ;
if ( ! parameters ) {
parameters = new Array < Function > ( paramTypes . length ) ;
constructorRegistry . set ( target , parameters ) ;
}
for ( var [ index , value ] of paramTypes . entries ( ) ) {
if ( typeof parameters [ index ] !== "function" ) {
parameters [ index ] = value ;
}
}
}
}
// usage
class FrontEnd extends FrontEndBase {
// @inject on property
@inject
public circularDependency : FrontEndBase ;
// @inject on parameters
constructor ( @inject user : UserServiceBase , @inject data : DataServiceBase ) {
}
}
// @inject on constructor
@inject
class UserService extends UserServiceBase {
constructor ( data : DataServiceBase ) {
}
}
// usage
let container = new CompositionContainer ( ) ;
container . for ( FrontEndBase ) . use ( FrontEnd ) ;
container . for ( UserServiceBase ) . use ( UserService ) ;
container . for ( DataServiceBase ) . use ( DataService ) ;
var frontEnd = container . get ( FrontEnd ) ;
@F ( "color" )
@G
class C {
constructor ( x : number , y : string ) {
}
}
function __decorate ( decorators , descriptor , mutator ) {
var value = mutator && descriptor [ mutator ] ;
if ( ! value && mutator === "descriptor" && typeof Object . getOwnPropertyDescriptor === "function" ) {
value = Object . getOwnPropertyDescriptor ( descriptor . target , descriptor . propertyKey ) ;
}
for ( var i = decorators . length - 1 ; i >= 0 ; i -- ) {
var decorator = decorators [ i ] ;
if ( mutator ) { descriptor [ mutator ] = value ; }
value = decorator ( descriptor ) || value ;
}
if ( mutator === "descriptor" && value && typeof Object . defineProperty === "function" ) {
Object . defineProperty ( descriptor . target , descriptor . propertyKey , value ) ;
}
return value ;
}
var C = ( function ( ) {
class C {
}
C = __decorate ( [ F ( "color" ) , G ] , { target : C , paramTypes : [ Number , String ] } , "target" ) ;
return C ;
} ) ( ) ;
class C {
@F ( "color" )
@G
method ( x : number , y : string ) : boolean {
}
}
var C = ( function ( ) {
class C {
method ( x , y ) {
}
}
__decorate ( [ F ( "color" ) , G ] , { target : C . prototype , propertyKey : "method" , type : Function , paramTypes : [ Number , String ] , returnType : Boolean } , "descriptor" ) ;
return C ;
} ) ( ) ;
Class Property Declaration (?)
class C {
@F ( "color" )
@G
property : string ;
}
var C = ( function ( ) {
class C {
}
__decorate ( [ F ( "color" ) , G ] , { target : C . prototype , propertyKey : "property" , type : String } , "descriptor" ) ;
} ) ( ) ;
class C {
method ( @F ( "color" ) @G p : number ) {
}
}
var C = ( function ( ) {
class C {
method ( p ) {
}
}
__decorate ( [ F ( "color" ) , G ] , { target : C . prototype . method , paramIndex : 0 , type : Number } ) ; // mutator is undefined
} ) ( ) ;