【问题标题】:How to combine multiple property decorators in Typescript?如何在 Typescript 中组合多个属性装饰器?
【发布时间】:2019-01-28 20:53:37
【问题描述】:

我有一个类 Template 有一个属性 _id 有来自 class-transformertyped-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;
}

现在我尝试将这两者组合成一个新的自定义属性装饰器:

/**
 *
 */
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,
};

如果我只返回Expose() 的结果,自定义装饰器就可以工作,但我不知道如何在@ExposeToGraphQL() 中组合@Expose@Type

【问题讨论】:

  • 如果你想让ExposeToGraphQL同时满足ExposeType的目的,对于初学者来说,它不需要采用与Type相同的参数吗?
  • 我以为以后会担心参数:)

标签: typescript decorator


【解决方案1】:
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);
  }
}

然后你可以按如下方式使用该装饰器:

class Template extends Typegoose {
    @ExposeToGraphQL(/*exposeOptions*/ undefined, /*typeFunction*/ () => String)
    @Field(() => ID)
    public _id?: mongoose.Types.ObjectId;
}

你可以找到装饰器in this link的官方文档。

@Expose@Type() 基本上是Decorator Factories。装饰工厂的主要用途:

  • 它返回一个函数
  • 该函数将在运行时调用(在类之后,在本例中为 Template,已定义),并带有 2 个参数:
    • 类原型(Template.prototype
    • 装饰器附加到的属性的名称 (_id)。

如果两个或多个装饰器附加到同一个属性(称为Decorator Composition),它们的评估如下:

  • 工厂函数的执行顺序与它们在代码中编写的顺序相同
  • 工厂函数返回的函数按逆序顺序执行

【讨论】:

    猜你喜欢
    • 2016-12-25
    • 2019-07-29
    • 1970-01-01
    • 2015-08-05
    • 1970-01-01
    • 2021-06-25
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多