dangcuuson / graphql-schema-typescript

Generate TypeScript from GraphQL's schema type definitions
190 stars 36 forks source link

typed resolvers #6

Closed jardakotesovec closed 6 years ago

jardakotesovec commented 6 years ago

Hi, this is great project, exactly what I was looking for!

As you say in readme, resolver result is any at this moment and can be explicitly defined in resolvers. I am wondering what was the reason to leave results as any? Are you considering to have option that would also type the results of resolvers?

dangcuuson commented 6 years ago

Hi jardakotesovec, I'm glad that you like this project :smile:

The reason I leave the resolve result default to any is because sometimes, the developer may not want to fully resolve the object, but leave some fields to be resolved in a lazy way due to expensive code if resolved directly.

For example, with this schema:

schema {
  query: RootQuery
}

type RootQuery {
  user: User
}

type User {
  username: String!
  email: String!
  # assuming this could be expensive due to additional database query
  history: [UserHistory!]
}

type UserHistory{
 # etc.
}

Then in the RootQueryToUserResolver function, they may want to resolve username and email only, and either wrap history in another resolve function, or completely ignore it and let UserToHistoryResolver to do its job. They may also want to return additional information to help UserToHistoryResolver resolve its type as well(although I can't think of a reason why).

However, now when you bring this up, I think I was overthinking back then. :smile: I believe I could make the lib to be a little "smart" by set the default resolve result of RootQueryToUserResolver to User instead of any, and developer can still overwrite them if they don't like it.

The same thinking process was applied for TParent as well.

A new option to have a smarter default type will be implemented soon!

dangcuuson commented 6 years ago

Btw if you have any idea or suggestion, please feel free to discuss them here.

jardakotesovec commented 6 years ago

@dangcuuson Thanks. I have started with typescript week ago.. so still in process to figure out what can be done with it :-).

I see that resolvers are most tricky in sense that you don't know how much stuff they should resolve. Technically (really just idea) I think you could expect fields which don't have own resolvers. But I can imagine it could get pretty complicated. Is clear what I mean?

But for parent and context type I don't see drawbacks if they are defined (but its from typescript newbie perspective). Especially it would be great if I could pass the context type via generics as its same for all resolvers.

jardakotesovec commented 6 years ago

@dangcuuson Had more time to think about. And now I see that parent and resolver result are pretty similar situation as you indicated. Both depends on the fact if there are additional resolvers for given type. Also it could theoretically depend on whats queried if someone using AST to determine what to resolve, but thats probably rare.

So simples improvement would be certainly the context type :-)

dangcuuson commented 6 years ago

I have added some options to make default TParent and TContext type not any

You can check new version (1.2.2) with these options: smartTParent smartTResult and asyncResult.

Happy coding :smile:

jardakotesovec commented 6 years ago

@dangcuuson Awesome! Will try it out next week. Closing this, I will open another issue if I have some particular issue with these updates :-). Thanks!

AndreiEzhov commented 5 years ago

@dangcuuson

I believe I could make the lib to be a little "smart" by set the default resolve result of RootQueryToUserResolver to User instead of any, and developer can still overwrite them if they don't like it.

I am using smartTParent, smartTResult and asyncResult, and I can't understand how to overwrite TResult. Do you have any examples?

AndreiEzhov commented 5 years ago

I'll try to explain myself better.

Let's say I'm using RootQueryToUserResolver, and I'm fetching from an API that returns some of the data I need, let's call the type UserModel. I get the error

Type 'RootQueryToUserResolver<unknown, UserModel | null>' is not assignable to type 'RootQueryToUserResolver<unknown, User | null>'

How would I write a class that implements RootQueryTypeResolver but overrides RootQueryToUserResolver so TResult is UserModel?

Love the project by the way 😄