I have a class Template
with a property _id
which has decorators from class-transformer
and typed-graphql
import {classToPlain, Exclude, Expose, plainToClass, Type } from 'class-transformer';
import { ExposeToGraphQL } from '../../decorators/exposeToGraphQL';
import { Field, ID, MiddlewareInterface, NextFn, ObjectType, ResolverData } from 'type-graphql';
import { getClassForDocument, InstanceType, prop, Typegoose } from 'typegoose';
/**
* Class
* @extends Typegoose
*/
@Exclude()
@ObjectType()
class Template extends Typegoose {
// @Expose and @Type should be both covered by ExposeToGraphQL
// @Expose()
@Type(() => String)
@ExposeToGraphQL()
@Field(() => ID)
public _id?: mongoose.Types.ObjectId;
}
Now I try to combine those two into a new custom property decorator:
/**
*
*/
import { Expose } from 'class-transformer';
import 'reflect-metadata';
const formatMetadataKey: Symbol = Symbol('ExposeToGraphQL');
function ExposeToGraphQL() {
console.log('ExposeToGraphQL');
return Expose();
}
function getExposeToGraphQL(target: any, propertyKey: string) {
console.log('getExposeToGraphQL');
return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
export {
ExposeToGraphQL,
getExposeToGraphQL,
};
The custom decorator works if I only return the result of Expose()
, but I don't know how to combine @Expose
and @Type
in @ExposeToGraphQL()
.
It's possible to use as many decorators on the same piece of code as you desire, and they'll be applied in the order that you declare them. This defines a class and applies three decorators — two to the class itself, and one to a property of the class: @log could log all access to the class.
Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript. NOTE Decorators are an experimental feature that may change in future releases.
The first parameter is commonly called target . The sealed decorator will be used only on class declarations, so your function will receive a single parameter, the target , which will be of type Function . This will be the constructor of the class that the decorator was applied to.
The expression for the method decorator function accepts three arguments. They are: Either the constructor function of the class for a static member or the prototype of the class for an instance member. The member name. The Property Descriptor for the member.
import { Expose, Type, TypeOptions, ExposeOptions } from 'class-transformer';
/**
* Combines @Expose then @Types decorators.
* @param exposeOptions options that passes to @Expose()
* @param typeFunction options that passes to @Type()
*/
function ExposeToGraphQL(exposeOptions?: ExposeOptions, typeFunction?: (type?: TypeOptions) => Function) {
const exposeFn = Expose(exposeOptions);
const typeFn = Type(typeFunction);
return function (target: any, key: string) {
typeFn(target, key);
exposeFn(target, key);
}
}
Then you can use that decorator as follow:
class Template extends Typegoose {
@ExposeToGraphQL(/*exposeOptions*/ undefined, /*typeFunction*/ () => String)
@Field(() => ID)
public _id?: mongoose.Types.ObjectId;
}
You can find official documentation for decorator in this link.
@Expose
and @Type()
are basically Decorator Factories. The main purpose of a decorator factory:
Template
, was defined) with 2 arguments:
Template.prototype
) _id
).If two or more decorators are attached to a same property (called as Decorator Composition), they are evaluated as follow:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With