跳至主要内容
Intro to Typescript

TypeScript 简明介绍

对于许多通过 JavaScript 入门编程的人来说,很容易爱上它低门槛和多功能的特性。JavaScript 可以在浏览器中运行,可以用记事本编写,逐行解释,并且不需要复杂的编译或工具。JavaScript 通过允许来自各种背景的开发人员轻松上手并开始编码,普及了软件开发。但是,JavaScript 的宽容性也带来了犯错和产生 bug 的机会。

考虑以下 JavaScript 程序

function add(a, b) {
  return a + b;
}

console.log(add(1, 2)); // 3

这是一个简单的加法程序,旨在接受两个数字并将它们相加,返回结果。当我们使用非数字的值调用此函数时,可能会开始发生意想不到的、通常是不可预测的事情。

我们实际上只想用数字来调用这个函数——否则就没有意义——事实上,如果你传递给它的值不是数字,你最终会得到通常是奇怪且不可预测的结果

console.log(add(1, "2")); // 12
console.log(add(1, true)); // 2
console.log(add(1, "hello")); // 1hello

JavaScript 是一种动态类型语言。这意味着我们存储在变量中的数据类型可以在运行时更改。这使得在我们的 JavaScript 代码中捕捉我们的意图变得复杂——即我们的 add 函数应该只用数字调用。

我们在这里看到发生的事情称为类型强制转换——JavaScript 自动将值从一种数据类型转换为另一种数据类型。这可能通过函数和运算符显式发生,或者在 JavaScript 在特定上下文中期望某种类型的值时隐式发生。隐式类型强制转换有时会导致意外结果,尤其是在复杂的表达式中。以下是一些情况

console.log(1 + "2"); // "12" (number 1 is converted to string)
console.log("2" + 1); // "21" (number 1 is converted to string)

console.log("5" - 1); // 4 (string "5" is converted to number)
console.log("5" * "2"); // 10 (both strings are converted to numbers)

console.log(0 == false); // true (number 0 is converted to false)
console.log(0 === false); // false (no type coercion, different types)

令人困惑,对吧?!

在 JavaScript 代码库中,我们能做的最好的事情是为我们的程序添加一些保护性检查,如果提供了无效值,这些检查将抛出错误。仅靠这些运行时检查来保护我们免受错误影响的问题是,我们经常在用户发现 bug 的同时发现 bug 已被引入到我们的代码中。那么,我们如何保护自己免受这种通常令人困惑的 JavaScript 行为的影响呢?

TypeScript 来救援

TypeScript 可以通过明确我们期望的类型来帮助我们描述代码的意图。TypeScript 是 JavaScript 的超集,它向语言添加了额外的类型信息。当您编译 TypeScript 时,会生成可以在任何地方运行的 JavaScript,因此非常容易逐步使用它来改善您的开发体验,而无需重建所有软件。

类型允许您在代码运行之前捕获代码中的错误。如果您意外地将错误类型的值分配给变量,您将收到编译错误。类型还使您的代码更易于阅读,因为您可以明确声明您期望的值类型。我们还可以使用工具使类型更加强大。代码编辑器和 IDE 具有内置工具,可以在您正确使用类型时帮助您自动完成代码。

我们如何添加类型注解?

您可以通过在函数参数名称后附加冒号 (:) 后跟所需的类型,在 TypeScript 中添加类型注解。如果我们扩展之前的 add 示例以将其转换为 TypeScript,它将如下所示

function add(x: number, y: number) {
  return x + y;
}

console.log(add(1, 2)); // 3

这是我们可以对代码进行的最简单的更改,使其更加健壮。现在编译器知道,任何尝试使用除两个数字之外的任何东西调用 add() 的代码都将在运行时失败,因此它将在编译时抛出错误,告诉您您的程序无效。

例如,如果我们尝试使用数字和字符串调用 add,我们将收到编译器错误

compiler error in VSCode

TypeScript 非常智能,可以根据您提供给它的信息为您推断程序中的某些类型,我们称之为“类型推断”。如果我们以上面的示例为基础进行扩展,添加我们可以添加的所有类型注解,它将如下所示

function add(x: number, y: number): number {
  return x + y;
}

const result: number = add(1, 1);
console.log(result);

在这里,我们为函数参数、add 函数的返回类型和变量 result 显式添加了注解。作为一般规则,开发人员添加“足够”的类型注解来告诉 TypeScript 编译器正在发生什么,并让它推断其余部分。在我们最初的示例中,通过向 xy 参数添加类型注解,TypeScript 编译器可以检查代码并意识到我们只添加两个数字,因此将推断函数返回类型和变量 result 的类型均为 number

即使您只使用 TypeScript 注解函数参数,您也会立即从代码中删除一整类错误。

将您的 TypeScript 转换回 JavaScript

如果您的项目是使用 Node 构建的,您将需要添加 typescript 包并运行 tsc 编译器工具。我们编写了一篇关于配置 TypeScript 编译器的介绍

Deno 内置了 TypeScript 编译器,因此如果您使用 Deno,则不需要任何其他配置或工具。Deno 开箱即用地支持 TypeScript,在执行源代码时自动将 TypeScript 转换为 JavaScript。

在客户端,您可以使用 Vite,这是一个与我们志同道合的工具,它可以为您进行类似的透明编译,因此如果您是前端开发人员,您仍然可以在您的代码中获得 TypeScript 的乐趣。

下一步

在我们的下一篇 Deno Bite 中,我们将讨论您在 TS 代码中需要的常见类型,以及如何使用它们构建更复杂的类型,以使您的代码清晰且无 bug!

您是否有任何希望我们涵盖的 TypeScript 主题?请在TwitterDiscord 上告诉我们!