我想创建自己的类控制器来处理快速请求。
我所拥有的:
控制器:
import { Request, Response } from 'express';
import { transvalidate } from './schema/transform-validate';
import { ClassConstructor } from 'class-transformer';
export abstract class Controller<QuerySchema extends object> {
querySchema?: ClassConstructor<QuerySchema>;
query?: QuerySchema;
constructor(
protected readonly req: Request,
protected readonly res: Response,
) {
if (this.querySchema) {
this.query = transvalidate(this.querySchema, this.req.query);
}
}
getQuery(): QuerySchema {
if (!this.query) {
throw new Error(
`Can't get query. Probably the querySchema is not provided.`,
);
}
return this.query;
}
abstract handle(): Promise<unknown>;
}GetCatsController:
import { Controller } from './controller';
import { GetCatsQuerySchema } from './schema/query.schema';
export class CatsController extends Controller<GetCatsQuerySchema> {
querySchema = GetCatsQuerySchema;
handle(): Promise<unknown> {
// here this.getQuery() returns transformed to GetCatsQuerySchema and validated req.query object
return Promise.resolve(undefined);
}
}GetCatsQuerySchema
import { IsInt, IsOptional } from 'class-validator';
import { Type } from 'class-transformer';
export class GetCatsQuerySchema {
@Type(() => Number)
@IsInt()
@IsOptional()
age?: string;
}transform-validate函数:
import 'reflect-metadata';
import { ClassConstructor, plainToClass } from 'class-transformer';
import { validateSync, ValidationError } from 'class-validator';
export const transvalidate = <T extends object>(
targetClass: ClassConstructor<T>,
rawData: unknown,
) => {
const transformedValue = plainToClass(targetClass, rawData);
const errors = validateSync(transformedValue);
if (errors.length) {
const errorMessages = getAllErrorMessages(errors);
throw new Error(errorMessages[0]);
}
return transformedValue;
};
const getAllErrorMessages = (errors: ValidationError[]) => {
const errorMessages: string[] = [];
errors.map((error) => {
if (error.constraints) {
errorMessages.push(...Object.values(error.constraints));
}
});
return errorMessages;
};但是我不喜欢在扩展控制器时每个类都应该提供QuerySchema:
class CatsController extends Controller<GetCatsQuerySchema> {相反,我希望找到一种在类属性中定义QuerySchema的方法:
export class CatsController extends Controller {
querySchema = GetCatsQuerySchema;有可能吗?
发布于 2021-07-02 19:30:51
如果类是泛型的,则必须显式指定类型参数。这是我绝对会选择的方法。
现在,如果类不是泛型,则不必指定泛型类型参数。唯一的问题是你需要而不是QuerySchema找到一种方式来说“使用派生类中的任何类型”。幸运的是,typescript支持多态this,这基本上意味着无论当前的类型是什么。我们可以使用多态this类型来提取派生类型中的querySchema的实际类型:
type QuerySchema<T extends {querySchema?: ClassConstructor<object>}> =
InstanceType<Exclude<T['querySchema'], undefined>>
export abstract class Controller {
querySchema?: ClassConstructor<object>;
query?: QuerySchema<this>;
constructor(
protected readonly req: Request,
protected readonly res: Response,
) {
if (this.querySchema) {
this.query = null!;
}
}
getQuery(): QuerySchema<this> {
// ...
}
abstract handle(): Promise<unknown>;
}
export class CatsController extends Controller {
querySchema = GetCatsQuerySchema;
handle(): Promise<unknown> {
this.getQuery().age
this.getQuery().age1 // error
return Promise.resolve(undefined);
}
}
export class GetCatsQuerySchema {
age?: string;
}这似乎是可行的,但由于条件类型的原因,您可能迟早会遇到赋值问题,所以我将坚持使用泛型方法。因此,使用风险自负。
https://stackoverflow.com/questions/68224225
复制相似问题