Web 开发领域不断发展,但有一件事始终不变:JavaScript 作为主要编程语言的地位,预计在未来相当长的一段时间内仍将保持这一地位。与 JavaScript 并肩出现的,是一系列工具,它们共同推动了全栈应用的高效开发。本书致力于探索这些技术发展。

我们将专注于全栈开发,结合 TypeScript 和多种前沿技术,通过构建一个实际项目来构建完整的应用。我们的实践项目将涉及构建一个类似 ChatGPT 功能的聊天应用,涵盖前端和后端技术,以及数据库和 API 集成。

本书不仅仅是指导你从头到尾编写一个应用的指南,它还旨在教你有效的开发模式,这些模式足够灵活,可以应用于你选择的各种技术。虽然假设你已经具备 JavaScript 和基本 Web 开发概念的基础知识,但书中介绍的每个新主题和方面都将进行详细解释,确保你对每个主题有深入而全面的理解。

在本书中,我们将首先探索 TypeScript,它是 Web 开发中的关键角色。TypeScript 的主要优势在于其类型系统,这显著提升了开发过程。我们将讨论 TypeScript 的历史,将其与 JavaScript 进行比较,并探讨其在提升代码质量和减少错误方面的优势。我们还将深入研究 TypeScript 的核心概念,如语法、类型、接口、类和泛型,以全面了解其工作原理。

随后,我们将转向后端开发,选择 Bun 作为我们的主要技术。截至 2023 年,Bun 是最有前途的后端运行时之一,以其与 TypeScript 的无缝集成而著称。我们将涵盖 Bun 的基础知识,包括设置环境、处理身份验证、路由、中间件、请求的数据验证、构建 REST API、使用代码质量工具(如 linter)、调试、日志记录、代码结构和有效的测试策略。

接下来,我们将深入了解数据库的使用,特别是 PostgreSQL,这是一款功能强大的基于 SQL 的数据库,广泛应用于各种场景。我们将讨论数据存储及其优化方法。重点将是使用 TypeScript 作为管理存储数据的接口。我们将从基本的增删改查(CRUD)操作入手,然后探讨如何使用库和对象关系映射器(ORM)从 TypeScript 与 PostgreSQL 交互。本节还将涵盖将 PostgreSQL 集成到我们的后端基础设施中,并优化其使用。

随后,我们将着手进行 API 集成,这对于我们的聊天应用至关重要。我们将使用 OpenAI 的 GPT API 来完成聊天功能。在将该 API 集成并配置到我们的后端时,我们将涵盖更广泛的主题,例如如何有效地编写外部服务集成、确保 API 响应的正确性,以及如何将 API 调用集成到我们的 REST 端点中。此外,我们还将讨论 OpenAI API 及其模型在 Web 开发中各种有益的应用场景。

本书的最后部分将专注于使用 Svelte 进行前端开发。Svelte 以其简单性、速度和对初学者的友好性而闻名,是构建 Web 界面的绝佳选择。我们将探讨单页应用框架中常见的响应式模式,并将其应用于使用 Svelte 构建聊天功能。这包括使用 TypeScript 设置开发环境、了解 Svelte 的核心概念和语法、将前端与我们的 REST API 集成,以及学习组件、路由、状态管理和样式设计。

此外,我们还将深入探讨 Svelte 代码的测试和调试,并讨论维护和扩展代码库的最佳实践。

本书的目标不仅仅是让你掌握所涵盖的具体技术,而是帮助你建立一个灵活的全栈开发思维框架。这个框架将为你提供在 Web 项目开发中选择任何技术或语言时都适用的宝贵概念和实践。让我们开始 TypeScript 的学习之旅。

在本章中,我们将介绍 TypeScript,涵盖其历史背景、与 JavaScript 的区别以及其优势。我们还将了解 TypeScript 的基本语法,为后续更高级的主题奠定基础。

以下是本章将要涵盖的主题列表:

  • TypeScript 的介绍及其发展历程
  • TypeScript 与 JavaScript 的关键区别
  • 使用 TypeScript 的优势
  • TypeScript 的基本语法

[代码库位置]( https://github.com/PacktPublishing/Full-Stack-Web-Development-with-TypeScript-5/tree/main/Chapter01 Full-Stack Source Code)

TypeScript 的介绍及其发展历程

JavaScript 的市场推广速度令人惊叹。Brendan Eich 仅用 10 天时间就开发出了它的第一个版本,旨在通过一种简单的脚本语言使网页具有交互性。随着时间的推移,JavaScript 逐渐成为 Web 开发中的主导力量,而应用程序也变得越来越复杂。

许多开发者批评 JavaScript 的设计缺乏优雅,经常指出其语言决策似乎不一致。JavaScript 确实以其古怪的行为而闻名。为了说明这一点,让我们来看两个常见的例子:

	4 / []  
	0 == ""  

第一个表达式的结果是 Infinity ,而第二个表达式的结果是 true 。这发生是因为在执行代码时发生了类型强制转换。

类型强制转换是指自动将数据类型从一种转换为另一种的过程。例如,当 [] 在数值上下文中使用时,它会被强制转换为 0 ,而 4 除以 0 的结果是 Infinity 。在第二个例子中, "" 首先被转换为 0 ,然后等式的两边变得相等。让我们同意,这确实令人困惑。

另一个人们经常指出的重大缺点是 JavaScript 是弱类型和动态类型的。为了解决这个问题,微软在 2012 年推出了 TypeScript。从那时起,JavaScript 和 TypeScript 都发生了许多变化。例如,现在在 JavaScript 中,你可以通过使用 === 比较运算符来避免第一个例子中的问题,该运算符在不进行类型强制的情况下比较值。

但 TypeScript 的主要优势仍然是它的静态类型系统,它从一开始就禁止了这样的比较,因为根据类型定义,数字不能等于字符串,所以在类型逻辑中这样的比较是没有意义的。这仅仅是严格类型系统为我们提供的众多好处之一。我们将在本章和下一章中进一步探讨它的更多好处。让我们更仔细地看看 TypeScript 与 JavaScript 的区别。

接口 在TypeScript中,接口用于定义一个对象的结构,指定对象应该包含哪些字段以及这些字段的类型。让我们创建一个简单的聊天对象接口,然后定义几个符合Chat类型的实例。我们将通过一个名为displayChat的函数来完成代码片段,该函数接受一个Chat类型的参数并打印其详细信息:

interface Chat {  
    name: string;  
    model: string;  
}  

const foodChat: Chat = { name: 'food recipes exploration', model: 'gpt-4' };  
const typescriptChat: Chat = { name: 'typescript teacher', model: 'gpt-3.5-turbo' };  

function displayChat(chat: Chat) {  
    console.log(`Chat: ${chat.name}, Model: ${chat.model}`);  
}

首先,我们定义了一个名为Chat的接口,其中包含两个字段:namemodel,它们的类型都是string。通过这种方式,我们创建了自己的类型,可以在变量类型注解中使用它,就像我们在“简单类型”部分开头使用基本类型一样。当我们将其用于变量时,这意味着分配给该变量的对象必须遵循接口的结构。

然后,我们定义了两个变量foodChattypescriptChat,它们都满足Chat接口。它们包含不同的数据,但都是Chat类型。displayChat函数接受任何满足Chat接口的参数,这意味着它是一个具有namemodel字段的对象,字段类型为string

如果尝试访问对象上不存在的属性,接口还会报错。接口可以被扩展,可以有可选属性,并且可以包含函数定义。我们将在后续章节中探索这些特性。

总结 在本章中,我们对TypeScript进行了简要介绍,包括它与JavaScript的关系、它的优缺点、它的历史以及一些基本功能。掌握了这些信息后,我们就可以更深入地了解TypeScript了。在下一章中,我们将介绍TypeScript的更高级方面:泛型、联合类型、类以及其类型系统的其他有用功能。