如何使用TypeScript设置Gatsby项目

来自菜鸟教程
跳转至:导航、​搜索

作为 Write for DOnations 计划的一部分,作者选择了 Diversity in Tech Fund 来接受捐赠。

介绍

TypeScript 是 JavaScript 的超集,它在构建时添加了可选的静态类型,从而减少了调试运行时错误。 多年来,它已发展成为 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-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 develop 在本地开发服务器上启动 Gatsby 站点。 有关此解决方案的更多信息,请阅读 GitHub 内存线程错误:ENOENT:没有此类文件或目录 Gatsby 错误。


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

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

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

对于本教程,您将只使用 <StaticImage /> 组件,因此您可以删除与 <Link /> 组件相关的代码,以及 h1 和 [ X166X] 元素。 您的文件将如下所示:

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 文件扩展名。 特别是,将 src/components 中的 header.js、layout.js 和 seo.js 和 src/pages 中的 index.js 更改为 header.tsx、layout.tsx、seo.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 文件有两个主要用途:建立 TypeScript 项目的根目录 (include) 和覆盖 TypeScript 编译器的默认配置 (compilerOptions)。 有几种方法可以创建此文件。 如果你用 npm 安装了 tsc 命令行工具,你可以用 tsc --init 创建一个新的 tsconfig 文件。 但是该文件随后会填充许多默认选项和注释。

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

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

[label 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 属性指向一个 array 文件名或路径,编译器知道从 TypeScript 转换为 JavaScript。

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

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

您可以通过访问 TypeScript 的 tsconfig 参考指南 了解有关这些不同选项的更多信息。

现在已经为 Gatsby 配置了 TypeScript,您将通过重构 src/components 和 src/pages 中的一些样板文件来完成 TypeScript 集成。

第 4 步 — 为 TypeScript 重构 seo.tsx

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

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

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

TypeScript 中的基本类型

TypeScript 支持 基本数据类型 ,包括:boolean、number 和 string。 与 JavaScript 相比,TypeScript 的主要语法差异是现在可以使用关联类型定义变量。

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

let num: number;
num = 0

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

let typeScriptIsAwesome: boolean;
typeScriptIsAwesome = true;

在此代码中,num 必须是 number,str 必须是 string,并且 typeScriptIsAwesome 必须是 [ X104X]。

现在您将检查 src/components 目录中的 seo.tsx 文件中的 defaultProps 和 propTypes 声明。 在编辑器中打开文件并查找以下突出显示的行:

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 的弱类型系统。 defaultProps 和 propTypes 使用导入的 PropsTypes 类显式声明。 例如,在 propTypes 对象的 meta prop(或 alias)中,它的值是一个对象数组,每个对象本身就是 [ X152X] 组件。 一些道具被标记为必需(isRequired),而另一些则不是,这意味着它们是可选的。

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

[label 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 来替换已删除的 defaultProps 和 propTypes 定义。

添加以下突出显示的行:

[label 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 接口的地方,您将显式声明 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 接口中被定义为必需属性.

最后,您可以通过设置类型来修改 metaDescription 和 defaultTitle 常量声明,在本例中为 string:

[label 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 查询。 在 seo.tsx 文件中,其中解构的 site 属性是使用 GraphQL 静态查询定义的,将其类型设置为 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 中的图像:

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

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

最后,您将使用 TypeScript 重构剩余的样板文件:layout.tsx 和 header.tsx。 与 seo.tsx 一样,这些组件文件位于 src/components 目录中。

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

[label 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 属性显示它的值是 PropTypes 类的 node 类型。 另外,它是必需的道具。 由于布局中的 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 变量中:

[label 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.tsx 和 layout.tsx 类似,使用相同的 prop 名称将 Header.defaultProps 和 Header.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 时,您的浏览器将呈现以下内容:

结论

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

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