babyfish-ct / graphql-ts-client

Typescript DSL for GraphQL.
MIT License
147 stars 20 forks source link

Type from request #30

Closed IceBlizz6 closed 11 months ago

IceBlizz6 commented 11 months ago

This is currently what i'm doing

const request = query$.session(
  sessionQuery$.user(
    user$
      .id
      .name
      .email
  )
)

interface User {
  id: string
  name: string
  email: string
}

async function makeRequest(): Promise<User> {
  return (await execute(request)).session.user!
}

function printUser(user: User): void {
  console.log(user.name + " - " + user.email)
}

The response from the GraphQL request needs to be referenced in the code. So i'm making a new interface to represent that data structure. (in this example that is User)

What i would like to do

const request = query$.session(
  sessionQuery$.user(
    user$
      .id
      .name
      .email
  )
)

type User = ResponseOf<request>()

async function makeRequest(): Promise<User> {
  return (await execute(request)).session.user!
}

function printUser(user: User): void {
  console.log(user.name + " - " + user.email)
}

I want to store the return type in a place so that it can be reused. type User here will be the equivalent of the User interface from earlier. But User type will now update when the request is updated.

A similar project named GraphQL zeus has done something similar. https://graphqleditor.com/docs/tools/zeus/basics/selector/

type InferredResponseType = InputType<GraphQLTypes['Query'], typeof drawCardQuery>;

Is there currently any way to do that i this library? If not then would you be able to implement it?

IceBlizz6 commented 11 months ago

Tried to ask ChatGPT for a possible solution. It gave me this:

type InputType<T> = T extends QueryFetcher<infer TData, any> ? TData : never

I don't entirely understand it, but it seems to work.

const request = query$.session(sessionQuery$.user(user$.id.name.email))
type User = NonNullable<InputType<typeof request>["session"]["user"]>

function printUser(user: User): void {
  console.log(user.name + " - " + user.email)
}

Maybe it could be included in the library?

robsonfj commented 11 months ago

Actually what you want is already supported... here an example using your code

import { ModelType } from 'graphql-ts-client-api'

const userFetcher = user$.id.name.email
const request = query$.session(sessionQuery$.user(userFetcher ))

type User = ModelType<typeof userFetcher>

async function makeRequest(): Promise<User> {
  return (await execute(request)).session.user!
}

function printUser(user: User): void {
  console.log(user.name + " - " + user.email)
}
IceBlizz6 commented 11 months ago

Thank you for that. Do you know where i can find this in the documentation?

robsonfj commented 11 months ago

the definition is here 2. ModelType

i found one example in the get-start-async.md in the 6. Change react code

being used in const [data, setData] = useState<ModelType<typeof EMPLOYEE_LIST_QUERY>>();

babyfish-ct commented 11 months ago

@robsonfj Thanks for your answer when I was busy.