Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for Collection typings #4416

Open
techfg opened this issue Jan 6, 2025 · 5 comments
Open

feat: add support for Collection typings #4416

techfg opened this issue Jan 6, 2025 · 5 comments

Comments

@techfg
Copy link
Collaborator

techfg commented Jan 6, 2025

Would like to see types generated for collections (and possibly other items like integrations, etc.) so aid in the development experience.

For example, if a Collection Stuff has fields name and description, there would be a collection type for Stuff, a record type for StuffRecord and each field typed based on its underlying type.

At minimum, getFieldValue<>('') could automatically resolve to the correct type based on the name of the field specified and also ensure that an invalid field name could not be specified as a paramter.

Ideally, there would be a way to do something like:

const stuffWire = api.wire.useWire<StuffWire>("stuff", context)
const stuffData: StuffRecord[] = stuffWire.getData()
stuffData.getFirstRecord().name
@zachelrath
Copy link
Contributor

Absolutely agree that this would be a huge improvement to the developer experience - getting type-safety for domain models is table-stakes these days in web development. If you're writing logic to be generic such that it can work with arbitrary wires / collections / fields, this isn't as important, but if you're working on a company-specific app, this is not just extremely helpful, but expected functionality.

We started down this road a while back with server-side Collection type generation, but so far the only app-specific type generation that was done was for Bots and SelectLists.

App-specific Types are generated into an app.d.ts file within the generated directory, and are then can be imported from @uesio/app/{bundleName}/{typeDirectory} , e.g. @uesio/app/acme/foo/selectlists

As I recall, I think the hangup with Collections was the complexity of typing Reference and Struct fields. I think getting an MVP for this that supports simpler field types would be a great start.

For the curious, the main entrypoint for the logic that generates app-specific types right now can be found here:

func GenerateAppTypeScriptTypes(out io.Writer, bs bundlestore.BundleStoreConnection) error {

@techfg
Copy link
Collaborator Author

techfg commented Jan 7, 2025

Zod might be helpful for this. Possibly take the metadata, roll a ZodObject and then use it to get the types. Just thinking out loud....

@zachelrath
Copy link
Contributor

Zod might be helpful for this. Possibly take the metadata, roll a ZodObject and then use it to get the types. Just thinking out loud....

Are you thinking about invoking Zod as a library from Go via exec, with an auto-generated TS file containing the schemas ? That is interesting --- more complex in the sense that we'd have to call out to Node from Go, but simpler in that building the Zod schema would be pretty simple, and then we'd just let Zod generate the output types. I haven't experimented with Zod's circular dependency handling but that might be helpful for self-referential Reference fields and other gnarly stuff.

Generating TS types straight from Go is really just some string output, not too bad. I'd probably just stick with that for simplicity.

@zachelrath
Copy link
Contributor

Ah yeah this is coming back to me now...

Trying to get typed Wire record responses, instead of PlainWireRecord which is what getFirstRecord(), etc. return, is that Wire response types are very dynamic. So, having the Wire API generate its types using something like Zod at runtime actually feels pretty essential, vs compiling them the Wire record response types server-side on View modification or something like that.

Need to think about this some more...

@techfg
Copy link
Collaborator Author

techfg commented Jan 7, 2025

Are you thinking about invoking Zod as a library from Go via exec, with an auto-generated TS file containing the schemas ?

Haven't looked at the existing code to see how it works for the current server side stuff but, at high-level, was thinking we could use the metadata from the yaml, construct Zod types based on that and then generate typings from the Zod objects. Likely we write a ts file with the Zod constructed objects, then invoke tsc/similar on the file via node. Haven't looked in to whether or not Zod has an golang API or a built-in way for it to generate its own typings.

That is interesting --- more complex in the sense that we'd have to call out to Node from Go, but simpler in that building the

I think we're going to have to implement a go to node paradigm for the usage of esbuild anyway (see #4388 (comment)).

Generating TS types straight from Go is really just some string output, not too bad. I'd probably just stick with that for simplicity.

Depending on complexity, possible solution - https://github.com/gzuidhof/tygo

Trying to get typed Wire record responses, instead of PlainWireRecord which is what getFirstRecord(), etc. return, is that Wire response types are very dynamic. So, having the Wire API generate its types using something like Zod at runtime actually feels pretty essential, vs compiling them the Wire record response types server-side on View modification or something like that.

Still learning the code base so some of this is lost on me, sorry. Are you saying that in some cases there isn't a way except for during runtime to actually know what the type might be?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants