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,我们将收到编译器错误
TypeScript 非常智能,可以根据您提供给它的信息为您推断程序中的某些类型,我们称之为“类型推断”。如果我们以上面的示例为基础进行扩展,添加我们可以添加的所有类型注解,它将如下所示
function add(x: number, y: number): number {
return x + y;
}
const result: number = add(1, 1);
console.log(result);
在这里,我们为函数参数、add
函数的返回类型和变量 result
显式添加了注解。作为一般规则,开发人员添加“足够”的类型注解来告诉 TypeScript 编译器正在发生什么,并让它推断其余部分。在我们最初的示例中,通过向 x
和 y
参数添加类型注解,TypeScript 编译器可以检查代码并意识到我们只添加两个数字,因此将推断函数返回类型和变量 result 的类型均为 number
。
即使您只使用 TypeScript 注解函数参数,您也会立即从代码中删除一整类错误。
将您的 TypeScript 转换回 JavaScript
如果您的项目是使用 Node 构建的,您将需要添加 typescript
包并运行 tsc
编译器工具。我们编写了一篇关于配置 TypeScript 编译器的介绍。
Deno 内置了 TypeScript 编译器,因此如果您使用 Deno,则不需要任何其他配置或工具。Deno 开箱即用地支持 TypeScript,在执行源代码时自动将 TypeScript 转换为 JavaScript。
在客户端,您可以使用 Vite,这是一个与我们志同道合的工具,它可以为您进行类似的透明编译,因此如果您是前端开发人员,您仍然可以在您的代码中获得 TypeScript 的乐趣。
下一步
在我们的下一篇 Deno Bite 中,我们将讨论您在 TS 代码中需要的常见类型,以及如何使用它们构建更复杂的类型,以使您的代码清晰且无 bug!