0no-co / gql.tada

🪄 Magical GraphQL query engine for TypeScript
https://gql-tada.0no.co
MIT License
2.52k stars 41 forks source link

RFC: Allow enums to be remapped like scalars #180

Closed Maximaximum closed 4 months ago

Maximaximum commented 5 months ago

Summary

It would be great if there was a configuration option to make gql.tada emit typescript enums instead of union types for graphql enums.

There is a huge difference between these, one of them is that a typescript enum is an object that gets it into the transpiled js code, unlike a union type.

Moreover, this would imrpove compatibility of tada.gql with other existing codegen libs, namely @graphql-codegen. This, in turn, would ease the adoption and migration process for existing projects. In my particular case, the lack of this feature is an actual blocker for migrating my existing projects to gql.tada.

Proposed Solution

Let’s say we have a following piece of graphql schema:

query {
  applicant {
    status: APPLICANT_STATUS
  }
}

Schema interpolation should return something like this:

export enum APPLICANT_STATUS {
  ONLINE: "ONLINE",
  OFFLINE: "OFFLINE",
  BLOCKED: "BLOCKED"
}

export type Applicant {
  status: APPLICANT_STATUS;
}

Whereas currently it returns

export enum APPLICANT_STATUS {
  ONLINE: "ONLINE",
  OFFLINE: "OFFLINE",
  BLOCKED: "BLOCKED"
}

export type Applicant {
  status: "ONLINE" | "OFFLINE" | "BLOCKED";
}

Requirements

Maximaximum commented 5 months ago

FWIW, I’m aware we were having this issue, which has been resolved https://github.com/0no-co/gql.tada/issues/44

However, it does not address the issue I’m describing here

kitten commented 5 months ago

This requires explicit codegen for each enum, and doesn't really achieve much. In fact, it introduces more problems that people aren't often aware of in TypeScript.

enums are value-unique and reference-incompatible in values, so once they're generated and used, they often must be used.

const enums on the other hand are still often value-unique, but at least reference-compatible in terms of the values they contain.

Basically to put it short:

Moreover, this would imrpove compatibility of tada.gql with other existing codegen libs, namely @graphql-codegen.

This is not an explicit goal of the project and there are a lot of “default” options that would need to change in GCG to be more compatible with gql.tada. Instead, we often take the approach of doing the right thing and generating correct & compatible types first, by default.


Related Threads:

sitharus commented 5 months ago

How about the ability to use existing enums, similar to the scalar mapping? I have a fork with the feature as my work needs it to integrate gql.tada in to a legacy codebase - without this the integration is impossible. If this is compatible with the project I can tidy up the code and make a PR. It's a pretty small change.

It does require manually mapping every enum, but that's kind of the point as we want to get away from the legacy eventually.

kitten commented 4 months ago

@sitharus: That's an excellent idea! 💯

I just pushed a PR to implement that, so no worries. I realised that it's a minimal change with Omit<Schema['types'], keyof Scalars> in introspection.tsaddIntrospectionScalars type, but I believe that may have a hidden cost for TypeScript’s type checker for huge schemas. The linked PR refactors the types a little, so we can differentiate between generated enum value types and the scalar types. This should also allow us to check enumValues against re-mapped types in the future.