Hebilicious/form-actions-nuxt

Type annotations get stripped away in generated code

Opened this issue · 3 comments

Environment

  • Operating System: Linux
  • Node Version: v20.8.1
  • Nuxt Version: 3.8.2
  • CLI Version: 3.10.0
  • Nitro Version: 2.7.2
  • Package Manager: bun@1.0.13
  • Builder: -
  • User Config: devtools, modules, typescript
  • Runtime Modules: @hebilicious/form-actions-nuxt@0.3.0
  • Build Modules: -

Reproduction

https://github.com/ohmree/reimagined-giggle

Describe the bug

In server/actions/foo.ts I pass a type parameter to getQuery which seems to be erased from the generated server/.generated/.loader/foo.get.ts.

diff --git a/server/actions/foo.ts b/server/.generated/.loader/foo.get.ts
index d740d5e..4bc0f19 100644
--- a/server/actions/foo.ts
+++ b/server/.generated/.loader/foo.get.ts
@@ -1,6 +1,5 @@
-export const loader = defineServerLoader(async event => {
-  const { id } = getQuery<{ id: string }>(event);
-  // This composable accepts an h3 event handler, you can use any logic that you
-  // want here, including database calls, etc.
+/** This file is auto-generated by the form-actions module. /!\ Do not modify it manually ! */ 
+export default defineServerLoader(async (event) => {
+  const { id } = getQuery(event);
   return { id };
 });

This causes volar to infer the type of result.id in pages/foo/[id].vue as a string | number | boolean | QueryValue[] | Record<string, any> | QueryValue[], which results in type errors for seemingly correct code.

Additional context

Trying to cast id in any other way before returning it from the loader seems to result in the same.

Also if I manually apply the type annotations from my source file to the generated file then typescript stops complaining.

Logs

No response

Hello @ohmree, that's a very good catch. We use esbuild to clean-up the code extracted from the loader, which strips the TS annotation here

const shaked = await transform(code, { treeShaking: true, loader: "ts" }) // ...we clean it with esbuild ...

That is overkill and we shouldn't really bother doing that, as when you build the project, the production files will be properly minified anyways. But the main issue that I have would be that these generated files could contain a bunch of duplicated logic. Not the end of the world, but I would prefer if we had a better way to properly extract each loader from the source files.

Would it not be possible for the generated foo.get.ts to cast its export usingas typeof import('/path/to/foo').loader or something along those lines?
Not the cleanest but I can't see why it won't work as a quick and dirty fix.

And have you looked at how sveltekit handles type safety for loaders and actions? Do you think it could be applicable here?

Would it not be possible for the generated foo.get.ts to cast its export usingas typeof import('/path/to/foo').loader or something along those lines? Not the cleanest but I can't see why it won't work as a quick and dirty fix.

And have you looked at how sveltekit handles type safety for loaders and actions? Do you think it could be applicable here?

Hopefully there's no need for that, as we use magicast to extract the loaders from the source files, it should just copy the loader from your source file and keep the TS annotations.

If that's not working, unfortunately we'll have to add some custom parsing to properly extract them from the source files.