nestjs 中装饰器盘点🌧

1,356 阅读8分钟

nestjs 的装饰器全部分布在 packages/common/decorators 文件中

export * from './core';
export * from './modules';
export * from './http';

装饰器基础

  1. typescript 装饰器参考: www.typescriptlang.org/docs/handbo…
  2. es6 装饰器: es6.ruanyifeng.com/#docs/decor…
  3. reflect-metadata 映射元数据:github.com/rbuckton/re…
  4. nestjs 元数据定义目录:packages/common/constants.ts
  • Reflect.defineMetadata
Reflect.defineMetadata(metadataKey, metadataValue, target);
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);
  • Reflect.getMetadata
let result = Reflect.getMetadataKeys(target);
let result = Reflect.getMetadataKeys(target, propertyKey);

装饰本质是修饰目标对象 Target 的 function 或者 class, 然后使用 @ 操作符表示这个是一个装饰器或者修饰器。

Catch 装饰器

import { FILTER_CATCH_EXCEPTIONS } from '../../constants';
import { Type } from '../../interfaces';

export function Catch(...exceptions: Type<any>[]): ClassDecorator {
  return (target: object) => {
    Reflect.defineMetadata(FILTER_CATCH_EXCEPTIONS, exceptions, target);
  };
}

Catch 之昂视器就是一个函数,返回了一个函数,所以使用的时候,需要调用。在目标Catch对象上,定义的一个元数据 FILTER_CATCH_EXCEPTIONS, 元数据对应的值是 exceptions

Controller 控制器装饰器

import {
  HOST_METADATA,
  PATH_METADATA,
  SCOPE_OPTIONS_METADATA,
} from '../../constants';
import { isString, isUndefined } from '../../utils/shared.utils';
import { ScopeOptions } from '../../interfaces/scope-options.interface';

// 控制器接口
export interface ControllerOptions extends ScopeOptions {
  path?: string;
  host?: string;
}

// 控制器重载
export function Controller(): ClassDecorator;
export function Controller(prefix: string): ClassDecorator;
export function Controller(options: ControllerOptions): ClassDecorator;
export function Controller(
  prefixOrOptions?: string | ControllerOptions,
): ClassDecorator {
  const defaultPath = '/';
  const [path, host, scopeOptions] = isUndefined(prefixOrOptions)
    ? [defaultPath, undefined, undefined]
    : isString(prefixOrOptions)
    ? [prefixOrOptions, undefined, undefined]
    : [
        prefixOrOptions.path || defaultPath,
        prefixOrOptions.host,
        { scope: prefixOrOptions.scope },
      ];

  return (target: object) => {
    Reflect.defineMetadata(PATH_METADATA, path, target);
    Reflect.defineMetadata(HOST_METADATA, host, target);
    Reflect.defineMetadata(SCOPE_OPTIONS_METADATA, scopeOptions, target);
  };
}

Controller 装饰器也是一个函数,返回的一个函数,所有 Controller 使用的时候需要调用。然后定义了元素数据:

  • PATH_METADATA 路径元数据
  • HOST_METADATA 域元数据
  • SCOPE_OPTIONS_METADATA 作用域元数据

Dependencies 依赖装饰器

export function flatten<T extends Array<unknown> = any>(
  arr: T,
): T extends Array<infer R> ? R : never {
  const flat = [].concat(...arr);
  return flat.some(Array.isArray) ? flatten(flat) : flat;
}


export const Dependencies = (
  ...dependencies: Array<unknown>
): ClassDecorator => {
  const flattenDeps = flatten(dependencies);
  return (target: object) => {
    Reflect.defineMetadata(PARAMTYPES_METADATA, flattenDeps, target);
  };
};

装饰器定义了 PARAMTYPES_METADATA 元数据 flattenDeps

exception-filters 异常过滤装饰器

export const UseFilters = (...filters: (ExceptionFilter | Function)[]) =>
  defineFiltersMetadata(...filters);
 
const defineFiltersMetadata = (...filters: (Function | ExceptionFilter)[]) => {
  return (target: any, key?: string, descriptor?: any) => {
    const isFilterValid = <T extends Function | Record<string, any>>(
      filter: T,
    ) =>
      filter &&
      (isFunction(filter) || isFunction((filter as Record<string, any>).catch));

    if (descriptor) {
      validateEach(
        target.constructor,
        filters,
        isFilterValid,
        '@UseFilters',
        'filter',
      );
      extendArrayMetadata(
        EXCEPTION_FILTERS_METADATA,
        filters,
        descriptor.value,
      );
      return descriptor;
    }
    validateEach(target, filters, isFilterValid, '@UseFilters', 'filter');
    extendArrayMetadata(EXCEPTION_FILTERS_METADATA, filters, target);
    return target;
  };
};

extendArrayMetadata

export function extendArrayMetadata<T extends Array<any>>(
  key: string,
  metadata: T,
  target,
) {
  const previousValue = Reflect.getMetadata(key, target) || [];
  const value = [...previousValue, ...metadata];
  Reflect.defineMetadata(key, value, target);
}

inject 注入器

import {
  PROPERTY_DEPS_METADATA,
  SELF_DECLARED_DEPS_METADATA,
} from '../../constants';
import { isFunction, isUndefined } from '../../utils/shared.utils';

export function Inject<T = any>(token?: T) {
  return (target: object, key: string | symbol, index?: number) => {
    token = token || Reflect.getMetadata('design:type', target, key);
    const type =
      token && isFunction(token) ? ((token as any) as Function).name : token;

    if (!isUndefined(index)) {
      let dependencies =
        Reflect.getMetadata(SELF_DECLARED_DEPS_METADATA, target) || [];

      dependencies = [...dependencies, { index, param: type }];
      Reflect.defineMetadata(SELF_DECLARED_DEPS_METADATA, dependencies, target);
      return;
    }
    let properties =
      Reflect.getMetadata(PROPERTY_DEPS_METADATA, target.constructor) || [];

    properties = [...properties, { key, type }];
    Reflect.defineMetadata(
      PROPERTY_DEPS_METADATA,
      properties,
      target.constructor,
    );
  };
}

定义了三个护具映射:

  • SELF_DECLARED_DEPS_METADATA
  • SELF_DECLARED_DEPS_METADATA
  • PROPERTY_DEPS_METADATA

injectable 可注入的装饰器

import { v4 as uuid } from 'uuid';
import { SCOPE_OPTIONS_METADATA } from '../../constants';
import { ScopeOptions } from '../../interfaces/scope-options.interface';
import { Type } from '../../interfaces/type.interface';

export function Injectable(options?: InjectableOptions): ClassDecorator {
  return (target: object) => {
    Reflect.defineMetadata(SCOPE_OPTIONS_METADATA, options, target);
  };
}

export function mixin(mixinClass: Type<any>) {
  Object.defineProperty(mixinClass, 'name', {
    value: uuid(),
  });
  Injectable()(mixinClass);
  return mixinClass;
}

定义元数据:

  • SCOPE_OPTIONS_METADATA 作用域元数据

optional 选项装饰器

import {
  OPTIONAL_DEPS_METADATA,
  OPTIONAL_PROPERTY_DEPS_METADATA,
} from '../../constants';
import { isUndefined } from '../../utils/shared.utils';

export function Optional() {
  return (target: object, key: string | symbol, index?: number) => {
    if (!isUndefined(index)) {
      const args = Reflect.getMetadata(OPTIONAL_DEPS_METADATA, target) || [];
      Reflect.defineMetadata(OPTIONAL_DEPS_METADATA, [...args, index], target);
      return;
    }
    const properties =
      Reflect.getMetadata(
        OPTIONAL_PROPERTY_DEPS_METADATA,
        target.constructor,
      ) || [];
    Reflect.defineMetadata(
      OPTIONAL_PROPERTY_DEPS_METADATA,
      [...properties, key],
      target.constructor,
    );
  };
}
  • 获取、定义元数据 OPTIONAL_DEPS_METADATA、OPTIONAL_PROPERTY_DEPS_METADATA

set-metadata 设置元数据装饰器

import { Logger } from '../../services/logger.service';

export type CustomDecorator<TKey = string> = MethodDecorator &
  ClassDecorator & {
    KEY: TKey;
  };

export const SetMetadata = <K = string, V = any>(
  metadataKey: K,
  metadataValue: V,
): CustomDecorator<K> => {
  const decoratorFactory = (target: object, key?: any, descriptor?: any) => {
    if (descriptor) {
      Reflect.defineMetadata(metadataKey, metadataValue, descriptor.value);
      return descriptor;
    }
    Reflect.defineMetadata(metadataKey, metadataValue, target);
    return target;
  };
  decoratorFactory.KEY = metadataKey;
  return decoratorFactory;
};

const logger = new Logger('ReflectMetadata');
/**
 * @deprecated
 */
export const ReflectMetadata = <K = any, V = any>(
  metadataKey: K,
  metadataValue: V,
) => {
  logger.warn(
    `DEPRECATED! The @ReflectMetadata() decorator has been deprecated within the 6.0.0 release. Please, use @SetMetadata() instead.`,
  );
  return SetMetadata(metadataKey, metadataValue);
};

本质是 Reflect.defineMetadata(metadataKey, metadataValue, target); 的封装,定义的装饰器的 decoratorFactory 工厂函数。

use-guards 使用守卫装饰器

import { GUARDS_METADATA } from '../../constants';
import { CanActivate } from '../../interfaces';
import { extendArrayMetadata } from '../../utils/extend-metadata.util';
import { isFunction } from '../../utils/shared.utils';
import { validateEach } from '../../utils/validate-each.util';

export function UseGuards(...guards: (CanActivate | Function)[]) {
  return (target: any, key?: string, descriptor?: any) => {
    const isValidGuard = <T extends Function | Record<string, any>>(guard: T) =>
      guard &&
      (isFunction(guard) ||
        isFunction((guard as Record<string, any>).canActivate));

    if (descriptor) {
      validateEach(
        target.constructor,
        guards,
        isValidGuard,
        '@UseGuards',
        'guard',
      );
      extendArrayMetadata(GUARDS_METADATA, guards, descriptor.value);
      return descriptor;
    }
    validateEach(target, guards, isValidGuard, '@UseGuards', 'guard');
    extendArrayMetadata(GUARDS_METADATA, guards, target);
    return target;
  };
}

使用 extendArrayMetadata 扩展的方式来定义元数据 GUARDS_METADATA、GUARDS_METADATA

UseInterceptors 使用拦截器装饰器

import { INTERCEPTORS_METADATA } from '../../constants';
import { NestInterceptor } from '../../interfaces';
import { extendArrayMetadata } from '../../utils/extend-metadata.util';
import { isFunction } from '../../utils/shared.utils';
import { validateEach } from '../../utils/validate-each.util';

export function UseInterceptors(
  ...interceptors: (NestInterceptor | Function)[]
) {
  return (target: any, key?: string, descriptor?: any) => {
    const isValidInterceptor = <T extends Function | Record<string, any>>(
      interceptor: T,
    ) =>
      interceptor &&
      (isFunction(interceptor) ||
        isFunction((interceptor as Record<string, any>).intercept));

    if (descriptor) {
      validateEach(
        target.constructor,
        interceptors,
        isValidInterceptor,
        '@UseInterceptors',
        'interceptor',
      );
      extendArrayMetadata(
        INTERCEPTORS_METADATA,
        interceptors,
        descriptor.value,
      );
      return descriptor;
    }
    validateEach(
      target,
      interceptors,
      isValidInterceptor,
      '@UseInterceptors',
      'interceptor',
    );
    extendArrayMetadata(INTERCEPTORS_METADATA, interceptors, target);
    return target;
  };
}
  • extendArrayMetadata 扩展元数据 INTERCEPTORS_METADATA

use-pipes 使用管子装饰器

import { PIPES_METADATA } from '../../constants';
import { PipeTransform } from '../../interfaces/index';
import { extendArrayMetadata } from '../../utils/extend-metadata.util';
import { isFunction } from '../../utils/shared.utils';
import { validateEach } from '../../utils/validate-each.util';

export function UsePipes(...pipes: (PipeTransform | Function)[]) {
  return (target: any, key?: string, descriptor?: any) => {
    const isPipeValid = <T extends Function | Record<string, any>>(pipe: T) =>
      pipe &&
      (isFunction(pipe) || isFunction((pipe as Record<string, any>).transform));

    if (descriptor) {
      extendArrayMetadata(PIPES_METADATA, pipes, descriptor.value);
      return descriptor;
    }
    validateEach(target, pipes, isPipeValid, '@UsePipes', 'pipe');
    extendArrayMetadata(PIPES_METADATA, pipes, target);
    return target;
  };
}

extendArrayMetadata 扩展 PIPES_METADATA 元数据.

http 相关的装饰器

request-mapping.decorator 请求映射装饰器

export const RequestMapping = (
  metadata: RequestMappingMetadata = defaultMetadata,
): MethodDecorator => {
  const pathMetadata = metadata[PATH_METADATA];
  const path = pathMetadata && pathMetadata.length ? pathMetadata : '/';
  const requestMethod = metadata[METHOD_METADATA] || RequestMethod.GET;

  return (target, key, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata(PATH_METADATA, path, descriptor.value);
    Reflect.defineMetadata(METHOD_METADATA, requestMethod, descriptor.value);
    return descriptor;
  };
};

路由参数装饰器

const createRouteParamDecorator = (paramtype: RouteParamtypes) => {
  return (data?: ParamData): ParameterDecorator => (target, key, index) => {
    const args =
      Reflect.getMetadata(ROUTE_ARGS_METADATA, target.constructor, key) || {};
    Reflect.defineMetadata(
      ROUTE_ARGS_METADATA,
      assignMetadata<RouteParamtypes, Record<number, RouteParamMetadata>>(
        args,
        paramtype,
        index,
        data,
      ),
      target.constructor,
      key,
    );
  };
};
const createPipesRouteParamDecorator = (paramtype: RouteParamtypes) => (
  data?: any,
  ...pipes: (Type<PipeTransform> | PipeTransform)[]
): ParameterDecorator => (target, key, index) => {
  const args =
    Reflect.getMetadata(ROUTE_ARGS_METADATA, target.constructor, key) || {};
  const hasParamData = isNil(data) || isString(data);
  const paramData = hasParamData ? data : undefined;
  const paramPipes = hasParamData ? pipes : [data, ...pipes];

  Reflect.defineMetadata(
    ROUTE_ARGS_METADATA,
    assignMetadata(args, paramtype, index, paramData, ...paramPipes),
    target.constructor,
    key,
  );
};
  • 请求、响应
export const Request: () => ParameterDecorator = createRouteParamDecorator(
  RouteParamtypes.REQUEST,
);

export const Response: () => ParameterDecorator = createRouteParamDecorator(
  RouteParamtypes.RESPONSE,
);
  • next
export const Next: () => ParameterDecorator = createRouteParamDecorator(
  RouteParamtypes.NEXT,
);
  • session
export const Session: () => ParameterDecorator = createRouteParamDecorator(
  RouteParamtypes.SESSION,
);
  • UploadedFile
export const UploadedFile: (
  fileKey?: string,
) => ParameterDecorator = createRouteParamDecorator(RouteParamtypes.FILE);

export const UploadedFiles: () => ParameterDecorator = createRouteParamDecorator(
  RouteParamtypes.FILES,
);
  • Header
export const Headers: (
  property?: string,
) => ParameterDecorator = createRouteParamDecorator(RouteParamtypes.HEADERS);
  • Query
export function Query(
  property?: string | (Type<PipeTransform> | PipeTransform),
  ...pipes: (Type<PipeTransform> | PipeTransform)[]
): ParameterDecorator {
  return createPipesRouteParamDecorator(RouteParamtypes.QUERY)(
    property,
    ...pipes,
  );
}
  • Body
export function Body(
  property?: string | (Type<PipeTransform> | PipeTransform),
  ...pipes: (Type<PipeTransform> | PipeTransform)[]
): ParameterDecorator {
  return createPipesRouteParamDecorator(RouteParamtypes.BODY)(
    property,
    ...pipes,
  );
}
  • Param
export function Param(
  property?: string | (Type<PipeTransform> | PipeTransform),
  ...pipes: (Type<PipeTransform> | PipeTransform)[]
): ParameterDecorator {
  return createPipesRouteParamDecorator(RouteParamtypes.PARAM)(
    property,
    ...pipes,
  );
}
  • HostParam
export function HostParam(
  property?: string | (Type<PipeTransform> | PipeTransform),
): ParameterDecorator {
  return createRouteParamDecorator(RouteParamtypes.HOST)(property);
}

http-code

export function HttpCode(statusCode: number): MethodDecorator {
  return (target: object, key, descriptor) => {
    Reflect.defineMetadata(HTTP_CODE_METADATA, statusCode, descriptor.value);
    return descriptor;
  };
}

create-route-param-metadata 创建路由参数元数据

export function createParamDecorator<
  FactoryData = any,
  FactoryInput = any,
  FactoryOutput = any
>(
  factory: CustomParamFactory<FactoryData, FactoryInput, FactoryOutput>,
  enhancers: ParamDecoratorEnhancer[] = [],
): (
  ...dataOrPipes: (Type<PipeTransform> | PipeTransform | FactoryData)[]
) => ParameterDecorator {
  const paramtype = uuid();
  return (
    data?,
    ...pipes: (Type<PipeTransform> | PipeTransform | FactoryData)[]
  ): ParameterDecorator => (target, key, index) => {
    const args =
      Reflect.getMetadata(ROUTE_ARGS_METADATA, target.constructor, key) || {};

    const isPipe = (pipe: any) =>
      pipe &&
      ((isFunction(pipe) &&
        pipe.prototype &&
        isFunction(pipe.prototype.transform)) ||
        isFunction(pipe.transform));

    const hasParamData = isNil(data) || !isPipe(data);
    const paramData = hasParamData ? (data as any) : undefined;
    const paramPipes = hasParamData ? pipes : [data, ...pipes];

    Reflect.defineMetadata(
      ROUTE_ARGS_METADATA,
      assignCustomMetadata(
        args,
        paramtype,
        index,
        factory,
        paramData,
        ...(paramPipes as PipeTransform[]),
      ),
      target.constructor,
      key,
    );
    enhancers.forEach(fn => fn(target, key, index));
  };
}

Render 渲染装饰器

export function Render(template: string): MethodDecorator {
  return (target: object, key, descriptor) => {
    Reflect.defineMetadata(RENDER_METADATA, template, descriptor.value);
    return descriptor;
  };

header 装饰器

export function Header(name: string, value: string): MethodDecorator {
  return (target: object, key, descriptor) => {
    extendArrayMetadata(HEADERS_METADATA, [{ name, value }], descriptor.value);
    return descriptor;
  };
}

redirect 重定向

export function Redirect(url: string, statusCode?: number): MethodDecorator {
  return (target: object, key, descriptor) => {
    Reflect.defineMetadata(
      REDIRECT_METADATA,
      { statusCode, url },
      descriptor.value,
    );
    return descriptor;
  };
}

模块装饰器

module 模块装饰器

export function Module(metadata: ModuleMetadata): ClassDecorator {
  const propsKeys = Object.keys(metadata);
  validateKeys(propsKeys);

  return (target: object) => {
    for (const property in metadata) {
      if (metadata.hasOwnProperty(property)) {
        Reflect.defineMetadata(property, (metadata as any)[property], target);
      }
    }
  };
}

single-scope 单作用域装饰器

export function SingleScope(): ClassDecorator {
  return (target: any) => {
    const Metatype = target as FunctionConstructor;
    const Type = class extends Metatype {
      constructor(...args: any[]) {
        super(...args);
      }
    };
    Reflect.defineMetadata(SHARED_MODULE_METADATA, true, Type);
    Object.defineProperty(Type, 'name', { value: target.name });
    return Type as any;
  };
}

global 全局装饰器

export function Global(): ClassDecorator {
  return (target: any) => {
    Reflect.defineMetadata(GLOBAL_MODULE_METADATA, true, target);
  };
}

graphql 装饰器

ArgsType 参数类型装饰器(类装饰器)

export function ArgsType(): ClassDecorator {
  return (target: Function) => {
    const metadata = {
      name: target.name,
      target,
    };
    LazyMetadataStorage.store(() =>
      TypeMetadataStorage.addArgsMetadata(metadata),
    );
    addClassTypeMetadata(target, ClassType.ARGS);
  };
}

参数装饰器

export function Args(
  propertyOrOptionsOrPipe?:
    | string
    | (Type<PipeTransform> | PipeTransform)
    | ArgsOptions,
  optionsOrPipe?: ArgsOptions | (Type<PipeTransform> | PipeTransform),
  ...pipes: (Type<PipeTransform> | PipeTransform)[]
): ParameterDecorator {
  const [property, argOptions, argPipes] = getArgsOptions(
    propertyOrOptionsOrPipe,
    optionsOrPipe,
    pipes,
  );

  return (target: Object, key: string, index: number) => {
    addPipesMetadata(GqlParamtype.ARGS, property, argPipes, target, key, index);

    LazyMetadataStorage.store(target.constructor as Type<unknown>, () => {
      const { typeFn: reflectedTypeFn, options } = reflectTypeFromMetadata({
        metadataKey: 'design:paramtypes',
        prototype: target,
        propertyKey: key,
        index: index,
        explicitTypeFn: argOptions.type,
        typeOptions: argOptions,
      });

      const metadata = {
        target: target.constructor,
        methodName: key,
        typeFn: reflectedTypeFn,
        index,
        options,
      };

      if (property && isString(property)) {
        TypeMetadataStorage.addMethodParamMetadata({
          kind: 'arg',
          name: property,
          description: argOptions.description,
          ...metadata,
        });
      } else {
        TypeMetadataStorage.addMethodParamMetadata({
          kind: 'args',
          ...metadata,
        });
      }
    });
  };
}

context 内容装饰器

export function Context(
  property?: string | (Type<PipeTransform> | PipeTransform),
  ...pipes: (Type<PipeTransform> | PipeTransform)[]
): ParameterDecorator {
  return createGqlPipesParamDecorator(GqlParamtype.CONTEXT)(property, ...pipes);
}

directive 指令装饰器

export function Directive(
  sdl: string,
): MethodDecorator & PropertyDecorator & ClassDecorator {
  return (target: Function | Object, key?: string | symbol) => {
    validateDirective(sdl);

    LazyMetadataStorage.store(() => {
      if (key) {
        TypeMetadataStorage.addDirectivePropertyMetadata({
          target: target.constructor,
          fieldName: key as string,
          sdl,
        });
      } else {
        TypeMetadataStorage.addDirectiveMetadata({
          target: target as Function,
          sdl,
        });
      }
    });
  };
}

Extensions 扩展装换器你

export function Extensions(
  value: Record<string, unknown>,
): MethodDecorator & ClassDecorator & PropertyDecorator {
  return (target: Function | object, propertyKey?: string | symbol) => {
    LazyMetadataStorage.store(() => {
      if (propertyKey) {
        TypeMetadataStorage.addExtensionsPropertyMetadata({
          target: target.constructor,
          fieldName: propertyKey as string,
          value,
        });
      } else {
        TypeMetadataStorage.addExtensionsMetadata({
          target: target as Function,
          value,
        });
      }
    });
  };
}

Field 字段装饰器

export function Field(
  typeOrOptions?: ReturnTypeFunc | FieldOptions,
  fieldOptions?: FieldOptions,
): PropertyDecorator & MethodDecorator {
  return (
    prototype: Object,
    propertyKey?: string,
    descriptor?: TypedPropertyDescriptor<any>,
  ) => {
    addFieldMetadata(
      typeOrOptions,
      fieldOptions,
      prototype,
      propertyKey,
      descriptor,
    );
  };
}

HideField 隐藏字段装饰器

export function HideField(): PropertyDecorator {
  return (target: Record<string, any>, propertyKey: string | symbol) => {};
}

Info 装饰器

export function Info(...pipes: (Type<PipeTransform> | PipeTransform)[]) {
  return createGqlPipesParamDecorator(GqlParamtype.INFO)(undefined, ...pipes);
}

InputType 输入类型装饰器

export function InputType(
  nameOrOptions?: string | InputTypeOptions,
  inputTypeOptions?: InputTypeOptions,
): ClassDecorator {
  const [name, options = {}] = isString(nameOrOptions)
    ? [nameOrOptions, inputTypeOptions]
    : [undefined, nameOrOptions];

  return target => {
    const metadata = {
      target,
      name: name || target.name,
      description: options.description,
      isAbstract: options.isAbstract,
    };
    LazyMetadataStorage.store(() =>
      TypeMetadataStorage.addInputTypeMetadata(metadata),
    );
    addClassTypeMetadata(target, ClassType.INPUT);
  };

InterfaceType 接口类型装饰器

export function InterfaceType(
  nameOrOptions?: string | InterfaceTypeOptions,
  interfaceOptions?: InterfaceTypeOptions,
): ClassDecorator {
  const [name, options = {}] = isString(nameOrOptions)
    ? [nameOrOptions, interfaceOptions]
    : [undefined, nameOrOptions];

  return target => {
    const metadata = {
      name: name || target.name,
      target,
      ...options,
    };
    LazyMetadataStorage.store(() =>
      TypeMetadataStorage.addInterfaceMetadata(metadata),
    );

    addClassTypeMetadata(target, ClassType.INTERFACE);
  };
}

Mutation 编译装饰器

export function Mutation(
  nameOrType?: string | ReturnTypeFunc,
  options: MutationOptions = {},
): MethodDecorator {
  return (target: Object | Function, key?: string, descriptor?: any) => {
    const name = isString(nameOrType)
      ? nameOrType
      : (options && options.name) || undefined;

    addResolverMetadata(Resolver.MUTATION, name, target, key, descriptor);

    LazyMetadataStorage.store(target.constructor as Type<unknown>, () => {
      if (!nameOrType || isString(nameOrType)) {
        throw new UndefinedReturnTypeError(Mutation.name, key);
      }

      const { typeFn, options: typeOptions } = reflectTypeFromMetadata({
        metadataKey: 'design:returntype',
        prototype: target,
        propertyKey: key,
        explicitTypeFn: nameOrType,
        typeOptions: options,
      });
      const metadata: ResolverTypeMetadata = {
        methodName: key,
        schemaName: options.name || key,
        target: target.constructor,
        typeFn,
        returnTypeOptions: typeOptions,
        description: options.description,
        deprecationReason: options.deprecationReason,
      };
      TypeMetadataStorage.addMutationMetadata(metadata);
    });
  };
}

ObjectType 对象类型装饰器

export function ObjectType(
  nameOrOptions?: string | ObjectTypeOptions,
  objectTypeOptions?: ObjectTypeOptions,
): ClassDecorator {
  const [name, options = {}] = isString(nameOrOptions)
    ? [nameOrOptions, objectTypeOptions]
    : [undefined, nameOrOptions];

  const interfaces = options.implements
    ? [].concat(options.implements)
    : undefined;
  return target => {
    const addObjectTypeMetadata = () =>
      TypeMetadataStorage.addObjectTypeMetadata({
        name: name || target.name,
        target,
        description: options.description,
        interfaces,
        isAbstract: options.isAbstract,
      });

    // This function must be called eagerly to allow resolvers
    // accessing the "name" property
    addObjectTypeMetadata();
    LazyMetadataStorage.store(addObjectTypeMetadata);

    addClassTypeMetadata(target, ClassType.OBJECT);
  };
}

Parent 装饰器

export const Parent: () => ParameterDecorator = createGqlParamDecorator(
  GqlParamtype.ROOT,
);

插件装饰器

export function Plugin(): ClassDecorator {
  return (target: Function) => {
    SetMetadata(PLUGIN_METADATA, true)(target);
  };
}

Query 查询装饰器

export function Query(
  nameOrType?: string | ReturnTypeFunc,
  options: QueryOptions = {},
): MethodDecorator {
  return (target: Object | Function, key?: string, descriptor?: any) => {
    const name = isString(nameOrType)
      ? nameOrType
      : (options && options.name) || undefined;

    addResolverMetadata(Resolver.QUERY, name, target, key, descriptor);

    LazyMetadataStorage.store(target.constructor as Type<unknown>, () => {
      if (!nameOrType || isString(nameOrType)) {
        throw new UndefinedReturnTypeError(Query.name, key);
      }

      const { typeFn, options: typeOptions } = reflectTypeFromMetadata({
        metadataKey: 'design:returntype',
        prototype: target,
        propertyKey: key,
        explicitTypeFn: nameOrType,
        typeOptions: options || {},
      });
      const metadata: ResolverTypeMetadata = {
        methodName: key,
        schemaName: options.name || key,
        target: target.constructor,
        typeFn,
        returnTypeOptions: typeOptions,
        description: options.description,
        deprecationReason: options.deprecationReason,
      };
      TypeMetadataStorage.addQueryMetadata(metadata);
    });
  };
}

ResolveField 决策字段装饰器

export function ResolveField(
  propertyNameOrFunc?: string | ReturnTypeFunc,
  typeFuncOrOptions?: ReturnTypeFunc | ResolveFieldOptions,
  resolveFieldOptions?: ResolveFieldOptions,
): MethodDecorator {
  return (
    target: Function | Record<string, any>,
    key?: string,
    descriptor?: any,
  ) => {
    // eslint-disable-next-line prefer-const
    let [propertyName, typeFunc, options] = isFunction(propertyNameOrFunc)
      ? typeFuncOrOptions && typeFuncOrOptions.name
        ? [typeFuncOrOptions.name, propertyNameOrFunc, typeFuncOrOptions]
        : [undefined, propertyNameOrFunc, typeFuncOrOptions]
      : [propertyNameOrFunc, typeFuncOrOptions, resolveFieldOptions];

    SetMetadata(RESOLVER_NAME_METADATA, propertyName)(target, key, descriptor);
    SetMetadata(RESOLVER_PROPERTY_METADATA, true)(target, key, descriptor);

    options = isObject(options)
      ? {
          name: propertyName as string,
          ...options,
        }
      : propertyName
      ? { name: propertyName as string }
      : {};

    LazyMetadataStorage.store(target.constructor as Type<unknown>, () => {
      let typeOptions: TypeOptions, typeFn: (type?: any) => GqlTypeReference;
      try {
        const implicitTypeMetadata = reflectTypeFromMetadata({
          metadataKey: 'design:returntype',
          prototype: target,
          propertyKey: key,
          explicitTypeFn: typeFunc as ReturnTypeFunc,
          typeOptions: options as any,
        });
        typeOptions = implicitTypeMetadata.options;
        typeFn = implicitTypeMetadata.typeFn;
      } catch {}

      TypeMetadataStorage.addResolverPropertyMetadata({
        kind: 'external',
        methodName: key,
        schemaName: options.name || key,
        target: target.constructor,
        typeFn,
        typeOptions,
        description: (options as ResolveFieldOptions).description,
        deprecationReason: (options as ResolveFieldOptions).deprecationReason,
        complexity: (options as ResolveFieldOptions).complexity,
      });
    });
  };
}

ResolveProperty 决策属性装饰器

export function ResolveProperty(
  propertyNameOrFunc?: string | ReturnTypeFunc,
  typeFuncOrOptions?: ReturnTypeFunc | ResolveFieldOptions,
  options?: ResolveFieldOptions,
): MethodDecorator {
  logger.warn(
    'The "@ResolveProperty()" decorator has been deprecated. Please, use the "@ResolveField()" decorator instead.',
  );
  return ResolveField(
    propertyNameOrFunc as string,
    typeFuncOrOptions as ReturnTypeFunc,
    options,
  );
}

ResolveReference 决策引用装饰器

export function ResolveReference(): MethodDecorator {
  return (
    target: Function | Object,
    key?: string | symbol,
    descriptor?: any,
  ) => {
    SetMetadata(RESOLVER_REFERENCE_METADATA, true)(target, key, descriptor);
  };
}

Resolver 装饰器

export function Resolver(
  nameOrTypeOrOptions?: string | ResolverTypeFn | Type<any> | ResolverOptions,
  options?: ResolverOptions,
): MethodDecorator & ClassDecorator {
  return (
    target: Object | Function,
    key?: string | symbol,
    descriptor?: any,
  ) => {
    const [nameOrType, resolverOptions] =
      typeof nameOrTypeOrOptions === 'object' && nameOrTypeOrOptions !== null
        ? [undefined, nameOrTypeOrOptions]
        : [nameOrTypeOrOptions as string | ResolverTypeFn | Type<any>, options];

    let name = nameOrType && getClassName(nameOrType);

    if (isFunction(nameOrType)) {
      const objectName = getObjectTypeNameIfExists(nameOrType as Function);
      objectName && (name = objectName);
    }
    addResolverMetadata(undefined, name, target, key, descriptor);

    if (!isString(nameOrType)) {
      LazyMetadataStorage.store(target as Type<unknown>, () => {
        const typeFn = getResolverTypeFn(nameOrType, target as Function);

        TypeMetadataStorage.addResolverMetadata({
          target: target as Function,
          typeFn: typeFn,
          isAbstract: (resolverOptions && resolverOptions.isAbstract) || false,
        });
      });
    }
  };
}

Root 根装饰器

export const Root: () => ParameterDecorator = createGqlParamDecorator(
  GqlParamtype.ROOT,
);

标量装饰器

export function Scalar(
  name: string,
  typeFunc?: ReturnTypeFunc,
): ClassDecorator {
  return (target, key?, descriptor?) => {
    SetMetadata(SCALAR_NAME_METADATA, name)(target, key, descriptor);
    SetMetadata(SCALAR_TYPE_METADATA, typeFunc)(target, key, descriptor);
  };
}

Subscription 订阅装饰器

export function Subscription(
  nameOrType?: string | ReturnTypeFunc,
  options: SubscriptionOptions = {},
): MethodDecorator {
  return (
    target: Record<string, any> | Function,
    key?: string,
    descriptor?: any,
  ) => {
    const name = isString(nameOrType)
      ? nameOrType
      : (options && options.name) || undefined;

    addResolverMetadata(Resolver.SUBSCRIPTION, name, target, key, descriptor);
    SetMetadata(SUBSCRIPTION_OPTIONS_METADATA, options)(
      target,
      key,
      descriptor,
    );

    LazyMetadataStorage.store(target.constructor as Type<unknown>, () => {
      if (!nameOrType || isString(nameOrType)) {
        throw new UndefinedReturnTypeError(Subscription.name, key);
      }

      const { typeFn, options: typeOptions } = reflectTypeFromMetadata({
        metadataKey: 'design:returntype',
        prototype: target,
        propertyKey: key,
        explicitTypeFn: nameOrType,
        typeOptions: options,
      });
      const metadata: ResolverTypeMetadata = {
        methodName: key,
        schemaName: options.name || key,
        target: target.constructor,
        typeFn,
        returnTypeOptions: typeOptions,
        description: options.description,
        deprecationReason: options.deprecationReason,
      };
      TypeMetadataStorage.addSubscriptionMetadata(metadata);
    });
  };
}

小结

nestjs 的装饰器的小结:

  1. 装饰器主要有两块,@nestjs/common/decorator@nestjs/graphql/decorator
  2. 装饰器主要用到了映射元数据 reflect-metadata
  3. ...