如何使用 TypeScript 设置 Gatsby 项目

作者选择了技术多样性基金来接受捐赠,作为Write for DOnations计划的一部分。

介绍

TypeScriptJavaScript的超集,它在构建时添加了可选的静态类型,从而减少了调试运行时错误。多年来,它已发展成为 JavaScript 的强大替代品。同时,Gatsby已成为创建静态网站的有用前端框架。TypeScript 的静态打字能力与像 Gatsby 这样的静态站点生成器配合得很好,而且 Gatsby 内置了对 TypeScript 编码的支持。

在本教程中,您将使用 Gatsby 的内置功能为 TypeScript 配置 Gatsby 项目。在本教程之后,您将学习如何将 TypeScript 集成到您的 Gatsby 项目中。

先决条件

步骤 1 — 创建新的 Gatsby 站点并删除样板

首先,您将创建 Gatsby 站点并确保您可以运行服务器并查看该站点。之后,您将删除一些未使用的样板文件和代码。这将设置您的项目以在后续步骤中进行编辑。

打开计算机的控制台/终端并运行以下命令:

  • gatsby new gatsby-typescript-tutorial

这将需要几秒钟才能运行,因为它会为 Gatsby 站点设置必要的样板文件和文件夹。完成后,cd进入项目目录:

  • cd gatsby-typescript-tutorial

为确保站点的开发环境可以正常启动,请运行以下命令:

  • gatsby develop

几秒钟后,您将在控制台中收到以下消息:

Output
... You can now view gatsby-starter-default in the browser. http://localhost:8000

通常,默认端口是:8000,但您可以通过运行更改它gatsby develop -p another_number

前往您首选的浏览器并http://localhost:8000在地址栏中输入以查找该站点。它看起来像这样:

Gatsby 默认入门站点

注意:插件gatsby-plugin-sharp版本 3.9.0存在一个已知问题,在构建 Gatsby 站点时可能会导致以下错误:

Output
ERROR ENOENT: no such file or directory, open 'your_file_path/gatsby-typescript-tutorial/.cache/caches/gatsby-plugin-sharp/diskstore-f6dcddbf3c9007cd2587894f75b5cd62.json'

此错误的解决方法是降级gatsby-plugin-sharp到 3.8.0 版。为此,请打开您的package.json文件并进行以下突出显示的更改:

[gatsby-typescript-tutorial/package.json]
...
  "dependencies": {
    "gatsby": "^3.9.0",
    "gatsby-plugin-gatsby-cloud": "^2.9.0",
    "gatsby-plugin-image": "^1.9.0",
    "gatsby-plugin-manifest": "^3.9.0",
    "gatsby-plugin-offline": "^4.9.0",
    "gatsby-plugin-react-helmet": "^4.9.0",
    "gatsby-plugin-sharp": "3.8.0",
    "gatsby-source-filesystem": "^3.9.0",
    "gatsby-transformer-sharp": "^3.9.0",
    "prop-types": "^15.7.2",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-helmet": "^6.1.0"
  },
...

保存文件,然后使用以下命令重新安装您的依赖项:

  • npm install

现在使用 Gatsby CLI 删除public.cache文件夹,以便可以使用新的依赖项列表重新构建它们:

  • gatsby clean

您现在可以在本地开发服务器上启动您的 Gatsby 站点gatsby develop有关此解决方案的更多信息,请阅读有关Error: ENOENT: no such file or directoryGatsby 错误GitHub 内存线程

接下来,您将删除所有不必要的文件。这包括gatsby-node.jsgatsby-browser.jsgatsby-ssr.js

  • rm gatsby-node.js
  • rm gatsby-browser.js
  • rm gatsby-ssr.js

接下来,要完成设置,您将从项目的索引页面中删除一些样板代码。在项目的根目录中,转到该src目录,pages然后打开该index.js文件。

在本教程中,您将只使用一个<StaticImage />组件,因此您可以删除与该<Link />组件相关的代码以及h1p元素。您的文件将如下所示:

gatsby-typescript-tutorial/src/pages/index.js
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"

import Layout from "../components/layout"
import Seo from "../components/seo"

const IndexPage = () => (
  <Layout>
    <Seo title="Home" />
    <StaticImage
      src="../images/gatsby-astronaut.png"
      width={300}
      quality={95}
      formats={["AUTO", "WEBP", "AVIF"]}
      alt="A Gatsby astronaut"
      style={{ marginBottom: `1.45rem` }}
    />
  </Layout>
)

export default IndexPage

保存并关闭文件。

现在您已经创建了您的项目并完成了一些初始设置,您已准备好安装必要的插件。

第 2 步 – 安装依赖项

为了在 Gatsby 中设置对 TypeScript 的支持,您需要一些额外的插件和依赖项,您将在此步骤中安装它们。

gatsby-plugin-typescript插件已经附带了一个新创建的 Gatsby 站点。除非您想更改其任何默认选项,否则您不必gatsby-config.js显式地将此插件添加到您的文件中。这个 Gatsby 插件使得在 TypeScript 中写入.ts.tsx文件成为可能。

由于您的应用可以读取 TypeScript 文件,因此您现在将 Gatsby 的 JavaScript 文件更改为 TypeScript 文件扩展名。特别是,变化header.jslayout.js以及seo.jssrc/componentsindex.jssrc/pagesheader.tsxlayout.tsxseo.tsx,和index.tsx

  • mv src/components/header.js src/components/header.tsx
  • mv src/components/layout.js src/components/layout.tsx
  • mv src/components/seo.js src/components/seo.tsx
  • mv src/pages/index.js src/pages/index.tsx

您正在使用该mv命令将文件重命名为第二个参数。.tsx是文件扩展名,因为这些文件使用JSX

gatsby-plugin-typescript但是,插件有一个重要的警告:它不包括构建时的类型检查(TypeScript 的核心功能)。如果您使用 VS Code,这不会成为问题,因为 TypeScript 是 Visual Studio 中支持的语言。但是如果你使用其他编辑器,比如Atom,你需要做一些额外的配置来获得完整的 TypeScript 开发体验。

由于 Gatsby 是基于 React 的框架,因此还建议添加一些额外的 React 相关类型。要为特定于 React 的类型添加类型检查,请运行以下命令:

  • npm add @types/react

要为与 React DOM 相关的类型添加类型检查,请使用以下命令:

  • npm add @types/react-dom

现在您已经熟悉了插件gatsby-plugin-typescript,您可以在下一步中为 TypeScript 配置 Gatsby 站点。

第 3 步 – 使用tsconfig.json文件为 Gatsby 配置 TypeScript

在此步骤中,您将创建一个tsconfig.json文件。一个tsconfig.json文件有两个主要目的:建立打字稿项目(根目录include)并重写打字稿编译器的默认配置(compilerOptions)。有几种方法可以创建此文件。如果您tsc安装了带有 npm命令行工具,则可以创建一个tsconfig带有tsc --init. 但是该文件随后填充了许多默认选项和注释。

相反,在您的目录 ( gatsby-typescript-project/)的根目录创建一个新文件并将其命名为tsconfig.json.

接下来,创建一个具有两个属性compilerOptions的对象,include填充以下代码:

gatsby-typescript-tutorial/tsconfig.json
 {
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "jsx": "preserve",
    "lib": ["dom", "es2015", "es2017"],
    "strict": true,
    "noEmit": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "removeComments": false
  },
  "include": ["./src/**/*"]
}

注意:

此配置部分基于
gatsby-starter-typescript-plus启动器。

保存此文件并在完成后关闭它。

include属性指向编译器知道要从 TypeScript 转换为 JavaScript 的文件名或路径数组

以下是对 中使用的每个选项的简要说明compilerOptions

  • module– 为项目设置模块系统;commonjs默认使用。
  • target– 根据您使用的 JavaScript 版本,此选项决定了哪些功能要降级,哪些要保留。如果您的项目部署到较旧的环境与较新的环境,这会很有帮助。
  • jsx– 设置如何在.tsx文件中处理 JSX preserve选项保持 JSX 不变。
  • lib-不同的JS库/ API的(指定类型定义的阵列domes2015等)。
  • strict– 当设置为 时true,这会在构建时启用 TypeScript 的类型检查功能。
  • noEmit– 由于 Gatsby 已经使用Babel将您的代码编译为可读的 JavaScript,因此您可以将此选项更改true为不使用 TypeScript。
  • isolatedModules– 选择 Babel 作为你的编译器/转译器,你选择一次编译一个文件,这可能会在运行时导致潜在的问题。将此选项设置为true允许 TypeScript 在您即将遇到此问题时发出警告。
  • esModuleIterop– 启用此选项允许您使用 CommonJS(您的 set module)和 ES 模块(导入和导出自定义变量和函数)以更好地协同工作并允许所有导入的命名空间对象。
  • noUnusedLocalsnoUnusedParamters– 如果您要创建未使用的局部变量或参数,启用这两个选项将禁用 TypeScript 通常会报告的错误。
  • removeComments– 将此设置为false(或根本不设置)允许在任何 TypeScript 文件转换为 JavaScript 后出现注释。

您可以了解更多关于这些不同的选择和更多的访问打字稿的参考指南tsconfig

现在,打字稿配置为盖茨比,你要通过重构你的一些样板文件,在完成您的打字稿整合src/componentssrc/pages

第 4 步 — 重构seo.tsxTypeScript

在此步骤中,您将向seo.tsx文件添加一些 TypeScript 语法这一步深入讲解了TypeScript的一些概念;下一步将展示如何以更简洁的方式重构其他样板代码。

TypeScript 的一个特点是其语法的灵活性。如果您不想显式地向变量添加类型,则不必这样做。Gatsby 相信在你的工作流程中采用 TypeScript “可以而且应该是渐进式的”,因此这一步将集中在三个核心的 TypeScript 概念上:

  • 基本类型
  • 定义类型和接口
  • 处理构建时错误

TypeScript 中的基本类型

打字稿支持基本数据类型包括:booleannumber,和string与 JavaScript 相比,TypeScript 在语法上的主要区别在于,现在可以使用关联类型定义变量。

例如,以下代码块显示了如何使用突出显示的代码分配基本类型:

let num: number;
num = 0

let str: string;
str = "TypeScript & Gatsby"

let typeScriptIsAwesome: boolean;
typeScriptIsAwesome = true;

在此代码中,num必须是numberstr必须是string,并且typeScriptIsAwesome必须是boolean

现在,您将检查目录中找到文件中defaultPropspropTypes声明在编辑器中打开文件并查找以下突出显示的行:seo.tsxsrc/components

gatsby-typescript-tutorial/src/components/seo.tsx
...
import * as React from "react"
import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

...
      ].concat(meta)}
    />
  )
}


SEO.defaultProps = {
  lang: `en`,
  meta: [],
  description: ``,
}

SEO.propTypes = {
  description: PropTypes.string,
  lang: PropTypes.string,
  meta: PropTypes.arrayOf(PropTypes.object),
  title: PropTypes.string.isRequired,
}

export default SEO

默认情况下,Gatsby 站点的 SEO 组件带有使用PropTypes. defaultPropspropTypes明确地宣布,使用进口PropsTypes类。例如,在对象的metaprop(或别名)中propTypes,它的值是一个对象数组,每个对象本身就是PropTypes组件的一个 prop 一些道具被标记为必需的 ( isRequired) 而另一些则没有,这意味着它们是可选的。

由于您使用的是 TypeScript,因此您将替换此打字系统。继续删除defaultPropspropTypes(以及文件顶部import语句PropTypes)。您的文件将如下所示:

gatsby-typescript-tutorial/src/components/seo.tsx
 ...
import * as React from "react"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"


...
      ].concat(meta)}
    />
  )
}

export default SEO

现在您已经删除了默认类型,您将使用 TypeScript 写出类型别名。

定义 TypeScript 接口

在 TypeScript 中,接口用于定义自定义类型的“形状”。这些用于表示复杂数据的值类型,如 React 组件和函数参数。在该seo.tsx文件中,您将构建一个interface来替换已删除defaultPropspropTypes定义。

添加以下突出显示的行:

gatsby-typescript-tutorial/src/components/seo.tsx
 ...
import * as React from "react"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

interface SEOProps {
  description?: string,
  lang?: string,
  meta?: Array<{name: string, content: string}>,
  title: string
}

...


该接口通过设置每个属性关联的数据类型以及根据需要用字符标记一些属性SEOProps来完成SEO.propTypes所做的工作?

键入函数

就像在 JavaScript 中一样,函数在 TypeScript 应用程序中扮演着重要的角色。您甚至可以通过指定传递给函数的参数的数据类型来键入函数。在该seo.tsx文件中,您现在将处理定义的SEO功能组件。SEOProps定义接口 for 的位置下,您将显式声明SEO组件函数参数的类型,以及SEOProps后面的返回类型

添加以下突出显示的代码:

gatsby-typescript-tutorial/src/components/seo.tsx
...
interface SEOProps {
  description?: string,
  lang?: string,
  meta?: Array<{name: string, content: string}>,
  title: string
}

function SEO({ description='', lang='en', meta=[], title }: SEOProps) {
  ...
}

在这里,您为SEO函数参数设置默认值,以便它们遵守接口,并使用: SEOProps. 请记住,您至少必须将 包含title在传递给SEO组件的参数列表中,因为它被定义为SEOProps您之前定义接口中的必需属性

最后,您可以通过设置它们的类型来修改metaDescriptiondefaultTitle常量声明,string在这种情况下:

gatsby-typescript-tutorial/src/components/seo.tsx
 ...
function SEO({ description='', lang='en', meta=[], title }: SEOProps) {
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )

  const metaDescription: string = description || site.siteMetadata.description
  const defaultTitle: string = site.siteMetadata?.title
...

TypeScript 中的另一种类型是any类型。对于您正在处理类型不明确或难以定义的变量的情况,将其any用作避免任何构建时错误的最后手段。

使用该any类型的一个示例是处理从第三方获取的数据,例如 API 请求或 GraphQL 查询。使用 GraphQL 静态查询定义seo.tsx解构site属性文件中,将其类型设置为any

gatsby-typescript-tutorial/src/components/seo.tsx
...
interface SEOProps {
  description?: string,
  lang?: string,
  meta?: Array<{name: string, content: string}>,
  title: string
}

function SEO({ description='', lang='en', meta=[], title }: Props) {
  const { site }: any = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )
  ...
}

保存并退出文件。

始终保持定义的值与其类型一致很重要。否则,您将通过 TypeScript 编译器看到构建时错误。

构建时错误

习惯于 TypeScript 在构建时捕获和报告的错误会很有帮助。这个想法是 TypeScript 在构建时捕获这些错误,主要是与类型相关的错误,从长远来看(在编译时),这减少了调试量。

发生构建时错误的一个示例是当您声明一种类型的变量但为其分配另一种类型的值时。如果您要将传递给SEO组件的关键字参数之一的值更改为不同类型之一,TypeScript 编译器将检测到不一致并报告错误。下面是这在 VSCode 中的样子:

当描述变量设置为数字时,VSCode 中的构建时错误。

错误说Type 'number' is not assignable to type 'string'这是因为,当您设置 时interface,您说该description属性的类型为string该值0的类型为number如果您将descriptionback的值更改为“字符串”,则错误消息将消失。

步骤 5 — 重构样板的其余部分

最后,您将使用 TypeScript:layout.tsxheader.tsx. seo.tsx,这些组件文件位于src/components目录中。

打开src/components/layout.tsx在底部,是定义的Layout.propTypes删除以下突出显示的行:

gatsby-typescript-tutorial/src/components/layout.tsx
 /**
 * Layout component that queries for data
 * with Gatsby's useStaticQuery component
 *
 * See: https://www.gatsbyjs.com/docs/use-static-query/
 */

import * as React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
...

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout

所述children支柱表明,它的值是类型的nodePropTypes类。另外,它是必需的道具。由于children布局中的内容可以是从简单文本到 React 子组件的任何内容,ReactNode因此通过在顶部附近导入并将其添加到界面来用作关联类型:

添加以下突出显示的行:

gatsby-typescript-tutorial/src/components/layout.tsx
...
import * as React from "react"
import { useStaticQuery, graphql } from "gatsby"

import Header from "./header"
import "./layout.css"

interface LayoutProps {
  children: ReactNode
}

const Layout = ({ children }: LayoutProps) => {
  ...

接下来,向data存储获取站点标题数据的 GraphQL 查询变量添加一个类型由于这个查询对象来自像 GraphQL 这样的第三方实体,所以给出data一个any类型。最后,将string类型添加siteTitle使用该数据变量中:

gatsby-typescript-tutorial/src/components/layout.tsx
 ...
const Layout = ({ children }: LayoutProps) => {
  const data: any = useStaticQuery(graphql`
  query MyQuery {
    site {
      siteMetadata {
        title
      }
    }
  }
`)

const siteTitle: string = data.site.siteMetadata?.title || `Title`

  return (
    <>
      <Header siteTitle={siteTitle} />
      <div
...

保存并关闭文件。

现在打开src/components/header.tsx文件。这个文件还带有预定义的道具类型,使用PropTypes类。seo.tsxlayout.tsx,更换Header.defaultPropsHeader.propTypes一个与interface使用相同的道具名称:

gatsby-typescript-tutorial/src/components/header.tsx
import * as React from "react"
import { Link } from "gatsby"

interface HeaderProps {
  siteTitle: string
}

const Header = ({ siteTitle }: HeaderProps) => (
  <header
    style={{
      background: `rebeccapurple`,
      marginBottom: `1.45rem`,
    }}
  >
    <div
      style={{
        margin: `0 auto`,
        maxWidth: 960,
        padding: `1.45rem 1.0875rem`,
      }}
    >
      <h1 style={{ margin: 0 }}>
        <Link
          to="/"
          style={{
            color: `white`,
            textDecoration: `none`,
          }}
        >
          {siteTitle}
        </Link>
      </h1>
    </div>
  </header>
)

export default Header

保存并关闭文件。

为 TypeScript 重构文件后,您现在可以重新启动服务器以确保一切正常。运行以下命令:

  • gatsby develop

当您导航到 时localhost:8000,您的浏览器将呈现以下内容:

Gatsby 默认开发页面

结论

TypeScript 的静态类型功能在将调试保持在最低限度方面大有帮助。它也是 Gatsby 站点的一种很好的语言,因为它默认受支持。Gatsby 本身是一个有用的前端工具,用于创建静态站点,例如登录页面。

您现在可以使用两种流行的工具。要了解有关 TypeScript 的更多信息以及您可以使用它做的所有事情,请转到我们的如何在 TypeScript 中编码系列

觉得文章有用?

点个广告表达一下你的爱意吧 !😁