nestjs 的装饰器全部分布在 packages/common/decorators 文件中
export * from './core';
export * from './modules';
export * from './http';
装饰器基础
- typescript 装饰器参考: www.typescriptlang.org/docs/handbo…
- es6 装饰器: es6.ruanyifeng.com/#docs/decor…
- reflect-metadata 映射元数据:github.com/rbuckton/re…
- 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 的装饰器的小结:
- 装饰器主要有两块,
@nestjs/common/decorator和@nestjs/graphql/decorator。 - 装饰器主要用到了映射元数据 reflect-metadata
- ...