hono icon indicating copy to clipboard operation
hono copied to clipboard

Pass a string field to c.json throws Type instantiation is excessively deep and possibly infinite.ts(2589)

Open kaio-eduardo opened this issue 1 year ago • 2 comments

What version of Hono are you using?

4.6.3

What runtime/platform is your app running on?

Node

What steps can reproduce the bug?

  1. Return a c.json with a string field
  2. Let it empty or add a . or /

What is the expected behavior?

No typescript errors

What do you see instead?

screen 2024-10-06 181643

Type instantiation is excessively deep and possibly infinite.ts(2589)

Additional information

If you add another character this error does not happen or if you delete the period.

typescript: ^5.6.2

kaio-eduardo avatar Oct 06 '24 21:10 kaio-eduardo

This seems to be due to the complex computed types in src/utils/types.ts. I would imagine that breaking these down into smaller definitions will help (based on this issue).

Something like this maybe? Happy to create a PR if this looks good maintainers.

// Intermediate types to simplify JSONParsed
type ToJSON<T> = T extends { toJSON(): infer J } ? J : never
type HandleInvalidJSON<T> = T extends InvalidJSONValue ? never : T
type HandleArray<T> = T extends ReadonlyArray<unknown>
  ? { [K in keyof T]: JSONParsed<InvalidToNull<T[K]>> }
  : T
type HandleSetMap<T> = T extends Set<unknown> | Map<unknown, unknown> ? {} : T
type HandleObject<T> = T extends object
  ? {
      [K in keyof OmitSymbolKeys<T> as IsInvalid<T[K]> extends true
        ? never
        : K]: boolean extends IsInvalid<T[K]> ? JSONParsed<T[K]> | undefined : JSONParsed<T[K]>
    }
  : T

// Simplified JSONParsed type
export type JSONParsed<T> = T extends JSONPrimitive
  ? T
  : ToJSON<T> extends never
  ? HandleInvalidJSON<HandleArray<HandleSetMap<HandleObject<T>>>>
  : JSONParsed<ToJSON<T>>

safwanyp avatar Oct 07 '24 13:10 safwanyp

Hi @kaio-eduardo

I can't reproduce it. Can you provide a minimal project to reproduce it?

yusukebe avatar Oct 13 '24 06:10 yusukebe

@yusukebe it can be reproduced by passing unknown to c.json

minimal reproduction:

image
import { Hono } from "jsr:@hono/hono@^4.6.11"

new Hono().get("/", (c) => c.json({} as unknown))
jsr:@hono/hono@^4.6.11
deno 2.1.2 (stable, release, aarch64-apple-darwin)
v8 13.0.245.12-rusty
typescript 5.6.2

scarf005 avatar Dec 03 '24 07:12 scarf005

@scarf005

Why do you need to add unknown? I can't help you if you want to add unknown.

yusukebe avatar Dec 03 '24 08:12 yusukebe

Why do you need to add unknown? I can't help you if you want to add unknown.

I want to return JSON file and not have type is excessively deep errors.

scarf005 avatar Dec 03 '24 08:12 scarf005

@scarf005

Sorry. I can't understand it. If you want our help, please provide a minimal project to reproduce it and show an interaction.

yusukebe avatar Dec 03 '24 09:12 yusukebe

Sorry. I can't understand it. If you want our help, please provide a minimal project to reproduce it and show an interaction.

import { Hono } from "jsr:@hono/hono@^4.6.11"

new Hono().get("/", async (c) => c.json(JSON.parse(await Deno.readTextFile("file.json")) as unknown))

sorry, i don't understand which part you don't understand. could you elaborate?

scarf005 avatar Dec 03 '24 09:12 scarf005

@scarf005

You can't use unknown. To prevent the type error, please use as any.

yusukebe avatar Dec 03 '24 09:12 yusukebe

The same error occurs when trying to reference ReturnType of c.json. reproduction: https://stackblitz.com/edit/github-a8gzkzvs

import { serve } from '@hono/node-server';
import { Hono, type Context } from 'hono';
import { createMiddleware } from 'hono/factory';

interface Env {
  Variables: {
    echo: (data: string) => ReturnType<Context['json']>;
    //                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //                      Type instantiation is excessively deep and possibly infinite.(2589)
  };
}

const echoMiddleware = createMiddleware<Env>(async (c, next) => {
  c.set('echo', (data) => c.json({ data }));
  await next();
});

const app = new Hono();

app.get('/', echoMiddleware, (c) => {
  return c.var.echo('Hello Hono!');
});

const port = 3000;
console.log(`Server is running on http://localhost:${port}`);

serve({
  fetch: app.fetch,
  port,
});

ghaaj avatar Dec 11 '24 16:12 ghaaj

Hi @ghaaj You can use this

interface Env {
  Variables: {
    echo: (data: string) => Response;
  };
}

Playground

The reason for that error, c.json contains the types of Variables

EdamAme-x avatar Dec 12 '24 00:12 EdamAme-x

@EdamAme-x Thank you! I'm thinking of using Response & TypedResponse<...> for more type safety. I am sorry for the extra notifications.

ghaaj avatar Dec 12 '24 05:12 ghaaj

Hmmm, I don't think that way would change the type safety.

EdamAme-x avatar Dec 12 '24 09:12 EdamAme-x

This issue has been marked as stale due to inactivity.

github-actions[bot] avatar Dec 20 '24 00:12 github-actions[bot]

Closing this issue due to inactivity.

github-actions[bot] avatar Dec 22 '24 00:12 github-actions[bot]