作者选择了技术多样性基金来接受捐赠,作为Write for DOnations计划的一部分。
介绍
TypeScript是JavaScript的超集,它在构建时添加了可选的静态类型,从而减少了调试运行时错误。多年来,它已发展成为 JavaScript 的强大替代品。同时,Gatsby已成为创建静态网站的有用前端框架。TypeScript 的静态打字能力与像 Gatsby 这样的静态站点生成器配合得很好,而且 Gatsby 内置了对 TypeScript 编码的支持。
在本教程中,您将使用 Gatsby 的内置功能为 TypeScript 配置 Gatsby 项目。在本教程之后,您将学习如何将 TypeScript 集成到您的 Gatsby 项目中。
先决条件
- 您需要同时安装Node和npm才能运行开发环境并分别处理与 TypeScript 或 Gatsby 相关的包。本教程使用 Node.js 版本 14.17.2 和 npm 版本 6.14.13 进行了测试。要在 macOS 或 Ubuntu 18.04 上安装,请按照如何在 macOS 上安装 Node.js 和创建本地开发环境或如何在 Ubuntu 20.04 上安装 Node.js 的使用 PPA 安装部分中的步骤进行操作。
- 您需要在您的计算机上安装 Gatsby CLI 命令行工具。要进行设置,请阅读如何设置您的第一个 Gatsby 站点的开头部分。本教程已经在 Gatsby v3.9.0 和 Gatsby CLI v3.9.0 上进行了测试。
- 您将需要足够的 JavaScript 知识,尤其是 ES6+ 语法,例如解构和导入/导出。您可以在了解 JavaScript 中的解构、Rest 参数和扩展语法和了解JavaScript 中的模块和导入和导出语句中找到有关这些主题的更多信息。
- 此外,您需要在您的机器上安装 TypeScript。为此,请参阅TypeScript 官方网站。如果您使用Visual Studio Code之外的编辑器,则可能需要执行一些额外的步骤,以确保 TypeScript 在构建时执行类型检查并显示任何错误。例如,如果您使用 Atom,则需要安装该
atom-typescript
软件包才能获得真正的 TypeScript 体验。如果您只想为您的项目下载 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 站点gatsby develop
。有关此解决方案的更多信息,请阅读有关Error: ENOENT: no such file or directory
Gatsby 错误的GitHub 内存线程。
接下来,您将删除所有不必要的文件。这包括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
和p
元素。您的文件将如下所示:
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.js
,layout.js
以及seo.js
在src/components
和index.js
中src/pages
到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
文件有两个主要目的:建立打字稿项目(根目录include
)并重写打字稿编译器的默认配置(compilerOptions
)。有几种方法可以创建此文件。如果您tsc
安装了带有 npm的命令行工具,则可以创建一个tsconfig
带有tsc --init
. 但是该文件随后填充了许多默认选项和注释。
相反,在您的目录 ( gatsby-typescript-project/
)的根目录创建一个新文件并将其命名为tsconfig.json
.
接下来,创建一个具有两个属性compilerOptions
和的对象,并include
填充以下代码:
{
"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的(指定类型定义的阵列dom
,es2015
等)。strict
– 当设置为 时true
,这会在构建时启用 TypeScript 的类型检查功能。noEmit
– 由于 Gatsby 已经使用Babel将您的代码编译为可读的 JavaScript,因此您可以将此选项更改true
为不使用 TypeScript。isolatedModules
– 选择 Babel 作为你的编译器/转译器,你选择一次编译一个文件,这可能会在运行时导致潜在的问题。将此选项设置为true
允许 TypeScript 在您即将遇到此问题时发出警告。esModuleIterop
– 启用此选项允许您使用 CommonJS(您的 setmodule
)和 ES 模块(导入和导出自定义变量和函数)以更好地协同工作并允许所有导入的命名空间对象。noUnusedLocals
和noUnusedParamters
– 如果您要创建未使用的局部变量或参数,启用这两个选项将禁用 TypeScript 通常会报告的错误。removeComments
– 将此设置为false
(或根本不设置)允许在任何 TypeScript 文件转换为 JavaScript 后出现注释。
您可以了解更多关于这些不同的选择和更多的访问打字稿的参考指南的tsconfig
。
现在,打字稿配置为盖茨比,你要通过重构你的一些样板文件,在完成您的打字稿整合src/components
和src/pages
。
第 4 步 — 重构seo.tsx
TypeScript
在此步骤中,您将向seo.tsx
文件添加一些 TypeScript 语法。这一步深入讲解了TypeScript的一些概念;下一步将展示如何以更简洁的方式重构其他样板代码。
TypeScript 的一个特点是其语法的灵活性。如果您不想显式地向变量添加类型,则不必这样做。Gatsby 相信在你的工作流程中采用 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
必须是boolean
。
现在,您将检查在目录中找到的文件中的defaultProps
和propTypes
声明。在编辑器中打开文件并查找以下突出显示的行:seo.tsx
src/components
...
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
类。例如,在对象的meta
prop(或别名)中propTypes
,它的值是一个对象数组,每个对象本身就是PropTypes
组件的一个 prop 。一些道具被标记为必需的 ( isRequired
) 而另一些则没有,这意味着它们是可选的。
由于您使用的是 TypeScript,因此您将替换此打字系统。继续删除defaultProps
和propTypes
(以及文件顶部的import
语句PropTypes
)。您的文件将如下所示:
...
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
定义。
添加以下突出显示的行:
...
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
后面的返回类型:
添加以下突出显示的代码:
...
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
在这种情况下:
...
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
:
...
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
back的值更改为“字符串”,则错误消息将消失。
步骤 5 — 重构样板的其余部分
最后,您将使用 TypeScript:layout.tsx
和header.tsx
. 像seo.tsx
,这些组件文件位于src/components
目录中。
打开src/components/layout.tsx
。在底部,是定义的Layout.propTypes
。删除以下突出显示的行:
/**
* 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
支柱表明,它的值是类型的node
每PropTypes
类。另外,它是必需的道具。由于children
布局中的内容可以是从简单文本到 React 子组件的任何内容,ReactNode
因此通过在顶部附近导入并将其添加到界面来用作关联类型:
添加以下突出显示的行:
...
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
使用该数据的变量中:
...
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
,更换Header.defaultProps
和Header.propTypes
一个与interface
使用相同的道具名称:
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 中编码系列。