fastify / fastify-type-provider-json-schema-to-ts

A Type Provider for json-schema-to-ts
MIT License
35 stars 9 forks source link

Error `TS(2589): Type instantiation is excessively deep and possibly infinite` #68

Closed BoscoDomingo closed 6 months ago

BoscoDomingo commented 7 months ago

Prerequisites

Fastify version

4.25.1

Plugin version

2.2.2

Node.js version

20.10

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

22.04.3 LTS

Description

I get error TS(2589): Type instantiation is excessively deep and possibly infinite whenever relying solely on this plugin. I have to manually create an interface or type per request(which defeats the whole purpose)

Steps to Reproduce

export const SampleController: FastifyPluginAsyncJsonSchemaToTs = async (fastify, _opts) => {
  fastify.post(
  "/test",
  {
    schema: {
      body: {
        type: "object",
        properties: {
                dateFrom: { type: "string", format: "date-time" },
        },
        required: ["dateFrom"],
      },
      response: {
        200: {
          type: "object",
          properties: {
            message: { type: "string" },
          },
        },
        400: {
          type: "object",
          properties: {
            error: { type: "string" },
            message: { type: "string" },
          },
        },
      },
    },
  },
  async (request, reply): Promise<void> => {
      const {dateFrom: dateString} = request.body; // Error
  };

But if I do

fastify.post<{ Body: { dateFrom: string } }>(...)

it works just fine. Issue is I don't want to have to manually define schemas and types, hence why I use this plugin.

Expected Behavior

I would expect the types to be successfully generated from the schema, with no manual definition from my side

mcollina commented 7 months ago

Thanks for reporting!

Can you provide steps to reproduce? We often need a reproducible example, e.g. some code that allows someone else to recreate your problem by just copying and pasting it. If it involves more than a couple of different file, create a new repository on GitHub and add a link to that.

123NeNaD commented 7 months ago

Got the same issue. The issue can be reproduced on the example from the package's home page:

import { FastifyPluginAsyncJsonSchemaToTs } from '@fastify/type-provider-json-schema-to-ts';
import fastify from 'fastify';

const server = fastify();

const plugin: FastifyPluginAsyncJsonSchemaToTs = async function (fastify, _opts) {
  fastify.get(
    '/',
    {
      schema: {
        body: {
          type: 'object',
          properties: {
            x: { type: 'string' },
            y: { type: 'number' },
            z: { type: 'boolean' },
          },
          required: ['x', 'y', 'z'],
        } as const,
      },
    },
    (req) => {
      /// The `x`, `y`, and `z` types are automatically inferred
      const { x, y, z } = req.body;
    }
  );
};

Packages:

"dependencies": {
  "@fastify/type-provider-json-schema-to-ts": "^2.2.2",
  "fastify": "^4.25.2"
}, 
"devDependencies": {
  "@types/node": "^20.10.5",
  "nodemon": "^3.0.2",
  "rimraf": "^5.0.5",
  "ts-node": "^10.9.2",
  "typescript": "^5.3.3"
}

tsconfig.json:

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "include": ["src/**/*.ts"],
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "strict": true,
    "resolveJsonModule": true,
    "removeComments": true,
    "newLine": "lf",
    "noUnusedLocals": true,
    "noFallthroughCasesInSwitch": true,
    "isolatedModules": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "lib": ["ESNext"],
    "outDir": "dist",
    "sourceMap": true
  }
}
BoscoDomingo commented 7 months ago

@mcollina What @123NeNaD did seems about right (very similar configs as mine except for ts-node and nodemon, as I use tsx and node).

It fails for any given schema which should be automatically inferred. For my case, you could simply use a fastify.register(SampleController) and then start the server.

mcollina commented 6 months ago

I can reproduce, but I ignore what can cause this or what the problem is with it.

I pushed a repo so it's easier to reproduce: https://github.com/mcollina/ftpjstt

cc @Uzlopak @climba03003 can you take a look?

mcollina commented 6 months ago

Note that the following works https://github.com/fastify/fastify-type-provider-json-schema-to-ts/blob/main/types/index.test-d.ts, so it's just the plugin helpers that are not working.

Worst case, we will remove them.

mcollina commented 6 months ago

cc @RafaelGSS

climba03003 commented 6 months ago

I can reproduce, but I ignore what can cause this or what the problem is with it.

Yes, it is a TypeScript issue or the library issue. It requires a lot of recursion on the types so TypeScript refused to resolve it.

https://github.com/ThomasAribart/json-schema-to-ts/blob/main/documentation/FAQs/i-get-a-type-instantiation-is-excessively-deep-and-potentially-infinite-error-what-should-i-do.md

I believe somewhere it exist a issue to allow configure the deepness of types. But forgotten which one it is.

mcollina commented 6 months ago

So we recommend we remove those accessor?

I think combining the inference of the parameters with the one of the plugin trigger this

Uzlopak commented 6 months ago

@mohammad0-0ahmad

Do you have any idea?

climba03003 commented 6 months ago

So we recommend we remove those accessor?

The problem is not about any exist helper inside the library. It exist because json-schema-to-ts is already complicated, and when it using with the auto resolution inside fastify the case becomes even worst. More generic and resolution on types means it needs deeper to resolve.

It is also why I never use type provider in any of my projects. To solve the problem, we need to either simplify the types in fastify or the upstream json-schema-to-ts

mcollina commented 6 months ago

That was my conclusion. Note that everything works correctly without the wrapping plugin types.. so we can remove them.

BoscoDomingo commented 6 months ago

That was my conclusion. Note that everything works correctly without the wrapping plugin types.. so we can remove them.

So how would this work with separation of plugins in files if we remove the helper types?

I would assume adding a fastify.withTypeProvider<JsonSchemaToTsProvider>() in every plugin is probably not the best, hence why the helper types exist.

Using fastify: FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, FastifyLoggerInstance, JsonSchemaToTsProvider> is a slightly better workaround, but still sub-optimal and annoying :/

jfet97 commented 6 months ago

I'll report here what I've written on Twitter replying to @mcollina. In the repro I noticed that there is an error in node_modules/@fastify/type-provider-json-schema-to-ts/dist/index.d.ts.

In that file JSONSchema7 is imported from json-schema-to-ts, but json-schema-to-ts version 2.12.0 (you have ^2.0.0 as dependency here) exports JSONSchema, not JSONSchema7. Fixing this mismatch has fixed the 'Type instantiation is excessively deep and possibly infinite' error of the repro.

This PR of yours has already taken care of this json-schema-to-ts change. Maybe you just need to release a new release of this package?

P.S. Fastify version is 4.25.2, you have ^4.0.0 as dependency.

image image image
mcollina commented 6 months ago

The problem is back in current main. I do not have time to dig into the problem much further as it does not seem solvable.

Would love a PR that add those back. Using .withTypeProvider is not so bad.

climba03003 commented 6 months ago

Double checked on the current main. It is indeed fixed by upgrading json-schema-to-ts to version 3. It is not released yet.

image

mcollina commented 6 months ago

@climba03003 please take a look at https://github.com/fastify/fastify-type-provider-json-schema-to-ts/pull/70. It does not look like it's fixed.