TypeScript 类型擦除和错误行为

TypeScript 类型擦除和错误行为

TypeScript是一种流行的编程语言,提供了诸如类型检查和类型注解等功能,帮助开发人员编写更健壮、可维护的代码。然而,当TypeScript代码被编译成JavaScript时,类型信息会在一个叫做类型擦除的过程中丢失。这可能导致在运行时发生难以诊断和修复的错误。

在本文中,我们将探讨类型擦除的概念在TypeScript中如何影响我们代码的错误行为。

类型擦除

类型擦除是在编译过程中从程序中移除类型信息的过程。在TypeScript中,这意味着我们在代码中添加的类型注解在代码被编译为JavaScript时会被移除。这是因为JavaScript没有像TypeScript那样的类型系统,所以类型信息在运行时是不需要的。

例如,考虑以下TypeScript代码 −

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

当这段代码编译成JavaScript时,生成的代码如下所示:

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

请注意,类型注解已经被移除,只剩下函数签名。这意味着在运行时,无法知道 ab 的类型,如果传递了错误类型的参数,将在运行时发生错误。

浏览器或运行时环境用于运行JavaScript代码,而不是TypeScript代码。所以,每次我们想要运行TypeScript代码时,会先将其转译为JavaScript。这个转译过程涉及到移除类型注解,因此在运行时提供的类型检查也会被移除。

错误行为

当类型信息被擦除时,本应由TypeScript编译器捕获的错误可能会在运行时发生。这可能会使我们在代码中诊断和修复错误更加困难。

示例1

例如,考虑以下TypeScript代码-

function add(a: number, b: number): number {
   return a + b;
}
console.log(`The result of addition operation is: ${add("1", "2")}`);

当这段代码编译为JavaScript时,类型注解将被移除,并且错误将被标记到控制台上。

Argument of type 'string' is not assignable to parameter of type 'number'.

以下是上述代码的Javascript代码:

function add(a, b) {
   return a + b;
}
console.log(`The result of addition operation is: ${add("1", "2")}`);

输出

The result of addition operation is: 12

运行时, console.log 语句将输出 “12” ,这不是我们预期的结果。这是因为我们向 add 函数传递了两个字符串而不是两个数字,并且由于类型信息被擦除,该函数能够在不抛出错误的情况下执行。为了解决这个问题,我们需要添加运行时检查,以确保传递给 add 的参数是实际的数字。

与其他传统编译器(如GCC或Clang)不同,TypeScript编译器(tsc)在遇到任何错误(类型相关的错误)时不会停止编译过程。它继续完成整个代码的编译。它只是在控制台上标记和显示错误,但仍然进行编译。

示例2:对象类型检查

另一个由于类型擦除可能导致的错误行为示例是对象属性。考虑以下TypeScript代码:

interface Person {
   name: string;
   age: number;
}

function printInfo(person: Person) {
   console.log(`The name is: {person.name}`);
   console.log(`The age is:{person.age}`);
   console.log(`The email is: ${person.email}`);
}

const john = { name: "John", age: 30, email: "john@example.com" };
printInfo(john);

在运行时,即使 john 对象有一个额外的 email 属性不是 Person 接口的一部分, printInfo 函数仍然会执行而不抛出错误。如果 printInfo 函数依赖于 Person 接口完整性,这可能导致意外的行为。要解决这个问题,我们需要添加运行时检查,以确保传递给 printNameperson 参数只包含 Person 接口中的属性。

在编译时,上述TypeScript代码将生成以下JavaScript代码-

function printInfo(person) {
   console.log("The name is: ".concat(person.name));
   console.log("The age is: ".concat(person.age));
   console.log("The email is: ".concat(person.email));
}
var john = { name: "John", age: 30, email: "john@example.com" };
printInfo(john);

输出

The name is: John
The age is: 30
The email is: john@example.com

在开发TypeScript编译器时的基本理念是在早期的开发阶段(包括类型和JavaScript错误)标记代码中的任何错误,但仍将其编译为JavaScript代码。

示例3:泛型类型检查

function identity<T>(value: T): T {
   return value;
}
console.log(`The returned value is: ${identity<number>("1")}`);

在这个例子中,我们有一个通用函数 identity ,它接受一个类型为 T 的值并返回不变。然而,我们传递给函数的是一个字符串而不是一个数字。 由于类型信息被擦除了,函数能够在不抛出错误的情况下执行,但结果并不是我们期望的。可以通过添加一个运行时检查来修复这个问题,以确保传递给函数的值实际上是类型 T 的。 在编译时,上述TypeScript代码将生成以下JavaScript代码-

function identity(value) {
   return value;
}
console.log("The returned value is: ".concat(identity("1")));

输出

The returned value is: 1

结论

类型擦除是在使用TypeScript时需要理解的一个重要概念。它可能会导致运行时的错误,这些错误很难诊断和修复,特别是当错误是由于传递了错误类型的参数或者对象属性与预期接口不匹配时。为了减轻这些错误,重要的是添加运行时检查,确保我们的代码表现如预期。此外,我们还可以使用诸如TypeScript的 unknown 类型和as关键字之类的工具来执行类型转换,确保我们的代码正确处理不同类型的数据。

总之,虽然TypeScript提供了强大的类型检查和类型注解,帮助我们编写更好的代码,但是了解语言的限制以及类型擦除如何影响运行时的错误行为非常重要。通过添加运行时检查并使用 unknownas 等工具,我们可以减轻这些错误,并编写出更健壮和可维护的代码。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程

TypeScript 精选笔记