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

Custom Scalars? #153

Closed
garrettm opened this issue Oct 14, 2017 · 33 comments · Fixed by #444
Closed

Custom Scalars? #153

garrettm opened this issue Oct 14, 2017 · 33 comments · Fixed by #444
Labels
plugins waiting-for-release Fixed/resolved, and waiting for the next stable release

Comments

@garrettm
Copy link

garrettm commented Oct 14, 2017

In Typescript, custom scalar types are emitted like:

export type Foo = any;

How can I make the emitted Foo refer to my existing types?

For example, if somewhere else in my code base, I have:

class Foo {
  bar: string

  someMethod() {
    ...
  }
}

I know this supports templating, but even with templating, I'm not sure how to make Foo in the generated types refer to my project's Foo. It seems like I'd need to import existing scalar definitions into my schema template? Or I'd need to define all my custom scalars in templates? Both of these sound pretty unmaintainable. Is there some convenient way to do this? Or is there an example for solving this sort of problem?

PS. Thank you for this package!

@dotansimha
Copy link
Owner

@garrettm
I think we can add a custom configuration per each generator, and pass it via gql-gen.json config file. this way we can add custom scalars mapping (and also an import from the file that contains the interface).

What do you think?

@garrettm
Copy link
Author

Correct me if I'm wrong, here's what I'm imagining, given what you said:

  • add an option for extern definitions of scalars
  • if set, gql-gen adds extra emits:
import * as Extern from './extern'
export type ScalarName = Extern.ScalarName

The user can export scalar types from this extern.ts file, and the TS compiler will complain if you forget one.

@dotansimha
Copy link
Owner

@garrettm yeah it makes sense.
I'm currently working on the generator-specific configuration, and then we will be able to implement this feature

@garrettm
Copy link
Author

garrettm commented Nov 1, 2017

@dotansimha sounds good. If you're interested in letting someone else do the work, point me in the direction when ready and I can take a look.

@danielkcz
Copy link
Contributor

I am curious if there is any progress on this? Would love to be able specify types for my scalars :)

@pleerock
Copy link

pleerock commented May 8, 2018

@dotansimha facing same issue here. In my case I have a simple scalar Date and I would like to avoid generator to add export type Date = any; in the output since I already have a Date object globally available.

@dotansimha
Copy link
Owner

I see, @pleerock . I am thinking about the right solution for this.

We can easily pass custom configuration, so maybe a map like that:

{
    config: {
        scalars: [
             { scalar: "Date", type: "Date" }
        ]
    }
}

And if you want to use a custom TypeScript type you wrote, for example: MyDateType and map it to a specific GraphQL Scalar, we might need import as well:

{
    config: {
        scalars: [
             { scalar: "Date", type: "MyDateType", import: "../../types/my-date-type" }
        ]
    }
}

And it will also add the import on top of the file.

What do you think?

@pleerock
Copy link

pleerock commented May 8, 2018

It will definitely resolve most of issues.

@jonaskello
Copy link
Contributor

I like the typescript solution. I actually came across a a use-case with scalars today that it would solve. My other idea was to patch the generated code to add an import and replace the generated type alias with a regex, but this solution is of course much nicer :-).

One note about the import. Lets say you want to do a named import, how would that work? Perhaps something like this could work:

{
    config: {
        imports: ["import {MyDateType}" from "../datelib", import {MyFooType} from "../foolib" ]
        scalars: [
             { scalar: "Date", type: "MyDateType"},
             { scalar: "Foo", type: "MyFooType"}
        ]
    }
}

@dotansimha
Copy link
Owner

dotansimha commented May 8, 2018

@jonaskello yeah you are right, your examples supports more use cases (such as named import, default import or any other way).

@Slessi
Copy link

Slessi commented Jul 25, 2018

For query/mutation code generation, I use apollo-cli, which has the flag --customScalarsPrefix when using codegen

// with --customScalarsPrefix=GQL
interface SomeType {
    date: GQLDate;
}

GQLDate will not be exported in the generated types, and I keep a separate .d.ts with

declare type GQLDate = Date;

Think this is a nice solution for people who either already have their types globally available, and/or want to avoid name collisions with similarly named types

Note: Not suggesting that apollo-cli can be used instead (it can't), just sharing as inspiration for a potential fix

@Slessi
Copy link

Slessi commented Aug 6, 2018

@dotansimha Since new #444 was released, there seems to be an issue with my JSON scalar type.

schema

scalar JSON

type foo {
  bar: JSON!
}

generated types

export type JSON = any; //  as before

export interface foo {
  bar: Json; // not as before (previously, i would see JSON here)
}

I'm aware of the new scalars option for gql-gen.json but this doesn't help me as it results in the following

export type JSON = MyFancyType; // ok

export interface foo {
  bar: Json; // Json != JSON
}

@kamilkisiela
Copy link
Collaborator

I published a canary version: 0.11.0-alpha.4c054a57

Could you check if it works for you?

Successfully published:

  • graphql-code-generator@0.11.0-alpha.4c054a57
  • graphql-codegen-compiler@0.11.0-alpha.4c054a57
  • graphql-codegen-core@0.11.0-alpha.4c054a57
  • codegen-templates-scripts@0.11.0-alpha.4c054a57
  • graphql-codegen-introspection-template@0.11.0-alpha.4c054a57
  • graphql-codegen-typescript-mongodb-template@0.11.0-alpha.4c054a57
  • graphql-codegen-typescript-react-apollo-template@0.11.0-alpha.4c054a57
  • graphql-codegen-typescript-template@0.11.0-alpha.4c054a57

@Slessi
Copy link

Slessi commented Aug 8, 2018

@kamilkisiela with 0.11.0-alpha.4c054a57 of generator & template, I now get

export type Json = any;

export interface foo {
  bar: Json;
}

This works but why can't it be JSON in full caps, as found in my schema?

scalar JSON

@elie222
Copy link

elie222 commented Jul 17, 2019

Is this still waiting for release?

@jonaskello
Copy link
Contributor

@elie222 You can use ScalarsMap now.

@teebszet
Copy link

teebszet commented Sep 12, 2019

I'm using typescript, typescript-apollo-angular plugins to generate the client
and graphql-iso-date on the server for scalar DateTime.

Does anyone know if adding the following:

config:
  scalars:
    DateTime: Date

will mean that any field returned from the fetch of DateTime type will be an instance of the JS Date class?

@dotansimha
Copy link
Owner

@teebszet yes, but note that you can't really send JS Date over the network, so it will probably get serialized and you'll get it as string in the client, so the server can use JS Date, but the client will get string.

@teebszet
Copy link

@teebszet yes, but note that you can't really send JS Date over the network, so it will probably get serialized and you'll get it as string in the client, so the server can use JS Date, but the client will get string.

@dotansimha yeah that makes sense. I guess it would be up to the typescript-apollo-angular plugin to initialise those DateTime fields as Date objects in the client. But I'm not sure if that is a feature that exists or not

@dotansimha
Copy link
Owner

@teebszet I think it should be done in Apollo client, during the runtime, and then you can reflect the status of data by using custom scalars in the codegen.
I think you can do that with Apollo Link.

@danielkcz
Copy link
Contributor

@dotansimha Do you have some useful resources on how it can be done universally with Apollo Link?

I've found this pretty old (but still active) feature request for Apollo client and it almost seems like it's still not possible. It would be really lovely to get ISO date automatically parsed and converted and along with correct typings, it would be a breeze.

This has especially become an issue with date-fns v2 which no longer supports passing a string. Only a Date or number. It's definitely fairly tedious doing that manually whenever there is a need to work with field that contains a stringified date.

@Slessi
Copy link

Slessi commented Oct 3, 2019

@FredyC use parseISO

The previous parse implementation was renamed to parseISO.

@finaxar-arthur
Copy link

Can anyone update on this? I am still not able to convert custom scalars. This is my codegen.yml but it doesn't work.

overwrite: true
schema: 'schema.graphql'
generates:
  src/generated/graphql.tsx:
    config:
      scalars:
        Long: number
        BigDecimal: number
    plugins:
      - 'typescript'
      - 'typescript-operations'
      - 'typescript-react-apollo'
      - 'typescript-graphql-files-modules'
      - 'typescript-document-nodes'
      - 'fragment-matcher'
  ./graphql.schema.json:
    plugins:
      - 'introspection'

@ardatan
Copy link
Collaborator

ardatan commented Sep 1, 2020

@finaxar-arthur What do you mean by converting custom scalars? If you have any issues, could you please create a new issue with a minimal reproduction?

@JCMais
Copy link

JCMais commented Jan 18, 2021

@finaxar-arthur the config must be at the top, like

overwrite: true
schema: 'schema.graphql'
config:
  scalars:
    Long: number
    BigDecimal: number

@Rockson
Copy link

Rockson commented Feb 9, 2021

Is there an example on how to configure custom scalars mapping them to custom types? How do you specify where should the custom types be imported from?

@dotansimha
Copy link
Owner

Is there an example on how to configure custom scalars mapping them to custom types? How do you specify where should the custom types be imported from?

You can use mappers format for scalars, we use it in other places as well, should look like that:

generates:
  types.ts:
    config:
      scalars:
        Date: "my-file#MyType"
    plugins:
      - typescript

@nandorojo
Copy link

Is there an example on how to configure custom scalars mapping them to custom types? How do you specify where should the custom types be imported from?

You can use mappers format for scalars, we use it in other places as well, should look like that:

generates:
  types.ts:
    config:
      scalars:
        Date: "my-file#MyType"
    plugins:
      - typescript

@dotansimha I'm new to this plugin, could you share what my-file looks like?

@prichodko
Copy link

@nandorojo it could be just a simple TypeScript file that exports a type which name you would use behind #.

For example:

// file: my-custom-type.ts

export type MyCustomType =  {
   id: string
}

then in codegen.yml you could do:

generates:
  types.ts:
    config:
      scalars:
        Date: "path/to/file/my-custom-type#MyCustomType"

@tjmgregory
Copy link

Noticing that this doesn't work for the typescript-operations plugin - it works for the root generated file made by the typescript plugin, but for each file made by typescript-operations with preset: near-operation-file, it sets the field to the type correctly, but it forgets to import it from the mapped location.

@prichodko
Copy link

prichodko commented Nov 30, 2021

@tjmgregory that's actually true. I ended up declaring the type globally.

declare global {
  declare type JsonObject = Prisma.JsonObject
}

@credcore-dave
Copy link

Is there an example on how to configure custom scalars mapping them to custom types? How do you specify where should the custom types be imported from?

You can use mappers format for scalars, we use it in other places as well, should look like that:

generates:
  types.ts:
    config:
      scalars:
        Date: "my-file#MyType"
    plugins:
      - typescript

I know resurrecting old issues is frowned upon but I stumbled on this issue needing to do exactly this today and I have to say it's an extremely powerful feature for a certain class of problems, so thank you so much for implementing it.

@hypeJunction
Copy link

@tjmgregory I was able to fix the issue by adding the path to scalar types to tsconfig.json under compilerOptions.types

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugins waiting-for-release Fixed/resolved, and waiting for the next stable release
Projects
None yet