在GraphQl Codegen中生成正确的类型而不是联合

发布于 2025-01-28 13:20:59 字数 1791 浏览 3 评论 0原文

我正在尝试迁移一个设置,该设置完全生成所有类型,就像服务器所拥有的类型一样,仅基于我们编写的文档节点。

我在.graphqlrc.js中具有这种配置

/** @type {import('graphql-config').IGraphQLConfig} */
const graphqlConfig = {
  schema: process.env.NEXT_PUBLIC_API_URL,
  documents: './src/graphql/**/*.ts',
  extensions: {
    codegen: {
      hooks: {
        afterAllFileWrite: ['prettier --write'],
      },
      generates: {
        './src/__generated__/graphql.ts': {
          plugins: [
            'typescript',
            'typescript-operations',
            {
              add: {
                content: '/* eslint-disable */',
              },
            },
          ],
          config: {
            disableDescriptions: true,
          },
        },
        './src/__generated__/introspection-result.ts': {
          plugins: ['fragment-matcher'],
          config: {
            useExplicitTyping: true,
          },
        },
      },
    },
  },
}

,这会生成以下类似的东西

export type QueryName = {
  __typename?: 'Query'
  resource?:
    | { __typename?: 'A' }
    | { __typename?: 'B' }
    | {
        __typename?: 'C'
        id: string
        prop1: any
        prop2: any
      }
}

,而不是我期望生成的东西。我期望

export type QueryName = {
  __typename?: 'Query'
  resource?: {
        __typename?: 'C'
        id: string
        prop1: any
        prop2: any
  }
}

c那样的问题。当前生成的类型将影响很多代码,而如果我能输出要实现的目标,我们只需要更改类型即可。

我已经尝试使用config找到在这里解决方案。请让我知道这是否可能,或者如果有什么东西可以解决这个问题。

提前致谢!

I am trying to migrate a setup which generates all the types exactly like what the server has into something which is based on just the document nodes that we've written.

I currenly have this configuration in .graphqlrc.js

/** @type {import('graphql-config').IGraphQLConfig} */
const graphqlConfig = {
  schema: process.env.NEXT_PUBLIC_API_URL,
  documents: './src/graphql/**/*.ts',
  extensions: {
    codegen: {
      hooks: {
        afterAllFileWrite: ['prettier --write'],
      },
      generates: {
        './src/__generated__/graphql.ts': {
          plugins: [
            'typescript',
            'typescript-operations',
            {
              add: {
                content: '/* eslint-disable */',
              },
            },
          ],
          config: {
            disableDescriptions: true,
          },
        },
        './src/__generated__/introspection-result.ts': {
          plugins: ['fragment-matcher'],
          config: {
            useExplicitTyping: true,
          },
        },
      },
    },
  },
}

and this generates something like below

export type QueryName = {
  __typename?: 'Query'
  resource?:
    | { __typename?: 'A' }
    | { __typename?: 'B' }
    | {
        __typename?: 'C'
        id: string
        prop1: any
        prop2: any
      }
}

that is not exactly what I was expecting to be generated. I am expecting something like

export type QueryName = {
  __typename?: 'Query'
  resource?: {
        __typename?: 'C'
        id: string
        prop1: any
        prop2: any
  }
}

as I am only querying for C. The types that is currently getting generated will affect a lot of codes whereas if I could output what I want to achieve, we only need to change the types.

I've tried playing with the config found here but could not find a solution. Please let me know if this is possible or if there's something I could take a look at to solve this.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谁许谁一生繁华 2025-02-04 13:20:59

最终,我最终使用 tiny-invariant 为此。考虑FF代码

const {data} = useUserQuery({variables: {id}});

// more codes here...

invariant(data.user.__typename === "User");

// now we should get the type that we want here

I eventually end up using tiny-invariant package for this. Consider the ff code

const {data} = useUserQuery({variables: {id}});

// more codes here...

invariant(data.user.__typename === "User");

// now we should get the type that we want here
我的痛♀有谁懂 2025-02-04 13:20:59

有一个很好的解决方案!

例如,您有类似的东西:

export type GetProductQuery = {
  __typename?: 'Query'
  product?:
    | { __typename: 'NotFound'; message: string }
    | {
        __typename: 'Product'
        id: string
        title: string
        currentPrice: number
      }
    | null
}

然后,可以使用 /a>实用程序类型

type QueryProductData = Extract<GetProductQuery['product'], { __typename: 'Product' }>
type QueryNotFoundData = Extract<GetProductQuery['product'], { __typename: 'NotFound' }>

从这些类型中,您将来可以构造任何类型。

There is a pretty good solution!

For example you have something like this:

export type GetProductQuery = {
  __typename?: 'Query'
  product?:
    | { __typename: 'NotFound'; message: string }
    | {
        __typename: 'Product'
        id: string
        title: string
        currentPrice: number
      }
    | null
}

Then, you can use the Extract utility type

type QueryProductData = Extract<GetProductQuery['product'], { __typename: 'Product' }>
type QueryNotFoundData = Extract<GetProductQuery['product'], { __typename: 'NotFound' }>

From these types, you can construct any type in the future.

生生漫 2025-02-04 13:20:59

您也可以做到

if (data.user.__typename === "User") { ... };

以确保其指代联盟内部的类型

You could also do

if (data.user.__typename === "User") { ... };

to ensure that its referring to the type within the union you need

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文