Преобразовать схему (@sinclair/typebox), которая находится в декораторе, в тип

В настоящее время я работаю над оверлеем Fastify, который я хотел бы сделать, цель — разработать декораторы для быстрого создания маршрутов. Я знаю, что fastify-decorators существует, я работаю с ним уже долгое время, но он не включает поставщиков типов с typebox (или что-то еще в этом роде), поэтому вам придется каждый раз переопределять типы. Пример:

Таким образом, разработчик должен выполнить двойную работу, даже если он уже типизировал свое тело (в примере выше). Если он его изменит, он также должен правильно его преобразовать. Это раздражает.

Вот почему я хотел бы создать декоратор (который также будет обрабатывать пользовательские ключи, чего fastify-decorators не делает), который в идеале будет выводить тип напрямую, без необходимости приведения. Пример:

Поэтому я думаю, что нам нужно создать пользовательский декоратор, а также абстрактный класс "RequestHandler". Для декоратора аргументы будут такими:

Я хочу именно такой результат, я не хочу, чтобы разработчику пришлось что-либо приводить или извлекать схему из декоратора, чтобы привести его быстрее.

Это довольно неприятно, потому что fastify позволяет использовать тип поставщика с библиотекой @fastify/type-provider-typebox:

Он работает очень хорошо, я знаю, что он работает совсем не так, как декоратор, и я не знаю, возможно ли реализовать результат, который я ищу, поэтому я прошу вашей помощи.

Заранее большое спасибо

Я попытался хорошенько изучить библиотеку fastify-decorators, которая, по-моему, просто замечательная, но, к сожалению, в ней нет типа поставщика из ее декораторов.

Затем я попытался посмотреть, смогу ли я манипулировать вещами с помощью следующей библиотеки: https://github.com/fastify/fastify-type-provider-typebox

Проблема здесь в том, что это не декоратор, и ему приходится извлекать свою схему, чтобы манипулировать ею в другом месте.

import { Type } from "@sinclair/typebox";
import {GET, RequestHandler} from "fastify-decorators";

@GET("test", {
    schema: {
        body: Type.Object({
            foo: Type.Number(),
            bar: Type.String()
        })
    }
})
export default class HelloRoute extends RequestHandler {

    async handle() {
        const body = <{foo: number, bar: string}>this.request.body; // Body is not typed
        body.foo // foo is typed !
    }
}
import { Type } from "@sinclair/typebox";
import {GET, RequestHandler} from "fastify-decorators";

@GET("test", {
    schema: {
        body: Type.Object({
            foo: Type.Number(),
            bar: Type.String()
        })
    }
})
export default class HelloRoute extends RequestHandler {

    async handle() {
        const body = this.request.body; // Body is not typed
        body.foo // TS2339: Property foo does not exist on type unknown
    }
}
export interface RouteOptions extends RouteShorthandOptions {     
    description: string;     
    // Here we can add additional options 
}  
export function ReGet(path: string, options: RouteOptions): ClassDecorator { /* ... */  }
$ npm i @fastify/type-provider-typebox
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import { Type } from '@sinclair/typebox'

import fastify from 'fastify'

const server = fastify().withTypeProvider<TypeBoxTypeProvider>()

server.get('/route', {
    schema: {
        querystring: Type.Object({
            foo: Type.Number(),
            bar: Type.String()
        })
    }
}, (request, reply) => {

    // type Query = { foo: number, bar: string }

    const { foo, bar } = request.query // type safe!
})
import {
  FastifyReply,
  FastifyRequest,
  RawRequestDefaultExpression,
  RawServerDefault,
  RawReplyDefaultExpression,
  ContextConfigDefault
} from 'fastify';
import { RouteGenericInterface } from 'fastify/types/route';
import { FastifySchema } from 'fastify/types/schema';
import { Type, TypeBoxTypeProvider } from '@fastify/type-provider-typebox';

export type FastifyRequestTypebox<TSchema extends FastifySchema> = FastifyRequest<
  RouteGenericInterface,
  RawServerDefault,
  RawRequestDefaultExpression<RawServerDefault>,
  TSchema,
  TypeBoxTypeProvider
>;

export type FastifyReplyTypebox<TSchema extends FastifySchema> = FastifyReply<
  RawServerDefault,
  RawRequestDefaultExpression,
  RawReplyDefaultExpression,
  RouteGenericInterface,
  ContextConfigDefault,
  TSchema,
  TypeBoxTypeProvider
>

export const CreateProductSchema = {
  body: Type.Object({
    name: Type.String(),
    price: Type.Number(),
  }),
  response: {
    201: Type.Object({
      id: Type.Number(),
    }),
  },
};

export const CreateProductHandler = (
  req: FastifyRequestTypebox<typeof CreateProductSchema>,
  reply: FastifyReplyTypebox<typeof CreateProductSchema>
) => {
  // The `name` and `price` types are automatically inferred
  const { name, price } = req.body;

  // The response body type is automatically inferred
  reply.status(201).send({ id: 'string-value' });
  //                       ^? error TS2322: Type 'string' is not assignable to type 'number'.
};
Ферапонт
Вопрос задан30 мая 2024 г.

1 Ответ

2
Ия
Ответ получен4 сентября 2024 г.

Ваш ответ

Загрузить файл.