为了使Gatsby+TypeScript更加舒适,可以使用gatsby-plugin-graphql-codegen进行配置

在 Gatsby + TypeScript 的架构中,有一个名为gatsby-plugin-graphql-codegen的库,可以自动生成GraphQL的类型定义。
使用这个库,从GraphQL获取的数据将自动添加类型,从而使开发变得相当方便。但是,我遇到了一些问题,所以我将在文章中总结概述和解决方案。

顺便提一下,在搭建 Gatsby + TypeScript 环境方面,这篇文章非常有参考价值。
将 Gatsby.js 完全转为 TypeScript – Qiita

环境

    • TypeScript 3.9.7

React 16.13.1

Gatsby 2.4.13

gatsby-plugin-graphql-codegen 2.7.1

這個結論

总的来说,在gatsby-config.js(.ts)中加载插件时,设置以下选项将使您感到快乐。

module.exports = {
  plugins: [
    // ...中略
    {
      resolve: 'gatsby-plugin-graphql-codegen',
      options: {
        codegenConfig: { maybeValue: 'T | undefined' }, // これを追加!
      },
    },
  ]
}

这是什么意思?

gatsby-plugin-graphql-codegen在从GraphQL查询生成类型时,将所有返回值都用名为Maybe的类型进行包装。

export type Maybe<T> = T | null;

由于从GraphQL获取的数据可能为null,因此这是一个有效的类型定义。
在TypeScript中,您可以使用Optional Chaining?.来安全地获取可为空的值。

例如,我最喜欢的颜色是蓝色。

以 Gatsby 的默认模板 gatsby-starter-default 为例,下面是一个使用 GraphQL 查询来加载图片的组件。

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"

const Image = () => {
  const data = useStaticQuery(graphql`
    query {
      placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
        childImageSharp {
          fluid(maxWidth: 300) {
            ...GatsbyImageSharpFluid
          }
        }
      }
    }
  `)

  return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
}

export default Image

如果将其转换为TypeScript,可以这样编写。

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"
import { ImageQuery } from "../../graphql-types"

const Image: React.FC = () => {
  const data = useStaticQuery<ImageQuery>(graphql`
    query Image {
      placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
        childImageSharp {
          fluid(maxWidth: 300) {
            ...GatsbyImageSharpFluid
          }
        }
      }
    }
  `)

  return <Img fluid={data.placeholderImage?.childImageSharp?.fluid} />
}

export default Image

gatsby-plugin-graphql-codegen会根据为query命名(如上所示的query Image)来自动生成graphql-types.ts中的类型定义,我们可以将其类型指定为useStaticQuery,这样data就会获得类型补全。对于Img组件,我们可以使用Optional Chainging来传递值,这样即使无法获取到图片,也不会导致运行时错误,而是会进行处理。

发生的事情

然而,根据tsconfig.json的设置,可能会发生类似于1以下的编译错误。

この呼び出しに一致するオーバーロードはありません。
  2 中 1 のオーバーロード, '(props: Readonly<GatsbyImageProps>): GatsbyImage' により、次のエラーが発生しました。
    型 'Pick<ImageSharpFluid, "base64" | "aspectRatio" | "src" | "srcSet" | "sizes"> | null | undefined' を
型 'FluidObject | FluidObject[] | undefined' に割り当てることはできません。
      型 'null' を型 'FluidObject | FluidObject[] | undefined' に割り当てることはできません。
  2 中 2 のオーバーロード, '(props: GatsbyImageProps, context?: any): GatsbyImage' により、次のエラーが発生しました。
    型 'Pick<ImageSharpFluid, "base64" | "aspectRatio" | "src" | "srcSet" | "sizes"> | null | undefined' を
型 'FluidObject | FluidObject[] | undefined' に割り当てることはできません。
      型 'null' を型 'FluidObject | FluidObject[] | undefined' に割り当てることはできません。

当我们提取要点时,它说“无法将null分配给undefined”。
gatsby-image组件的Img已经被定义为可以接受undefined,但似乎无法接受null。
正如之前所述,gatsby-plugin-graphql-codegen会使用Maybe = T | null来包装所有类型,因此data.placeholderImage?.childImageSharp?.fluid可能被判断为null。
要避免这种情况,可以按以下方式编写,即当为null时自动变为undefined。

const Image: React.FC = () => {
  // ...略
  return <Img fluid={data.placeholderImage?.childImageSharp?.fluid ?? undefined} />
}

export default Image

只是说实话,对于从GraphQL获取的所有数据来说,这样做相当困难。特别是在React组件中,可选的props定义经常是T | undefined,所以会经常发生从null到undefined的转换。

或许可以改变的那种形式 de

我們回到開頭的結論,當插件加載時,需記錄以下設置。

module.exports = {
  plugins: [
    // ...中略
    {
      resolve: 'gatsby-plugin-graphql-codegen',
      options: {
        codegenConfig: { maybeValue: 'T | undefined' }, // これを追加!
      },
    },
  ]
}

您可以通过 codegenConfig.maybeValue 来覆盖生成的 Maybe 定义。
通过将 T | null 替换为 T | undefined,可以将可空值统一为 undefined,从而只需使用简单的 Optional Chaining 来编写。

const Image: React.FC = () => {
  // ...略
  return <Img fluid={data.placeholderImage?.childImageSharp?.fluid} />
}

export default Image

改变类型定义没问题吗?

我认为,将null自动视为undefined并不会有问题。因为它只是改变了类型定义,并且至少对转码后的JavaScript没有影响。我认为,如果使用最新的库,null和undefined之间的区别不会引发重大问题,但我并没有检查所有情况。如果有问题,请谅解。

总结

gatsby-plugin-graphql-codegenの生成するnullに悩まされている方はcodegenConfig: { maybeValue: ‘T | undefined’ }を設定すると快適になるかもしれません

将“严格”设置为true等等
广告
将在 10 秒后关闭
bannerAds