理解 Typescript 中的高级概念

2025-06-08

理解 Typescript 中的高级概念

本文由 Aaron Xie 撰写,最初发表于Educative, Inc.

许多开发者在使用 JavaScript 时,都经历过令人头痛的调试。运行程序,发现新的 bug,然后反复调试。经过数小时的调试,问题终于解决了。对于像 JavaScript 这样无法编译的编程语言来说,这是一个常见问题。

为了解决 JavaScript 的不足,微软创建了 TypeScript。随着越来越多的团队意识到将 TypeScript 纳入其技术栈的好处,越来越多的开发人员需要了解它。

今天,您将学习 TypeScript 中的一些高级概念,以便成为专家。

您将学习:

  • 什么是 TypeScript?

  • TypeScript 的优点和局限性

  • 严格类型简介

  • TypeScript 和面向对象编程

  • TypeScript 中的类型

  • 其他需要学习的主题

  • 总结和资源

什么是 TypeScript?

TypeScript由 Microsoft 创建和维护,是 JavaScript 的超集,这意味着所有函数式 JavaScript 代码在 TypeScript 下都有效。该语言可以理解为“用于应用程序规模开发的 JavaScript”,主要有两个重点:

  • 向当前 JavaScript 引擎提供未来 JavaScript 引擎的功能

  • 为 JavaScript 提供类型系统

TypeScript 的组件通常是语言本身(本质上是 JavaScript 加上附加功能和语法)、将代码转换为 JavaScript 的编译器以及语言服务(在编译器管道末端附近提供类似编辑器的应用程序)。

那么,为什么要使用 TypeScript?

  • 类型: TypeScript 提供静态类型,许多大型团队(如微软和谷歌)发现这有助于简化开发流程。

  • 面向对象编程: TypeScript 支持面向对象编程概念,如接口、继承、类等。

  • 编译:与解释性语言 JavaScript 不同,TypeScript 会为您编译代码并查找编译错误,从而使调试更加容易。

替代文本

安装 TypeScript

在深入研究 TypeScript 之前,请确保你已经成功安装了 TypeScript。获取 TypeScript 工具的主要方式有两种:通过 npm(Node.js 包管理器)或安装 TypeScript 的 Visual Studio 插件。

新公共管理(NPM):

安装

> npm install -g typescript

编译

> tsc helloworld.ts

如果您没有使用 NPM,您可以通过此链接下载 TypeScript 。

TypeScript 的优点和局限性

打字

JavaScript 是一种动态类型语言,这意味着类型错误只能在运行时发现。对于从事复杂项目的大型团队来说,这可能是一个很大的缺点,因为事先发现代码中的所有错误会容易得多。

TypeScript 提供可选的静态类型,使变量无法更改其类型,并且只能接受某些值。这种类型有助于 TypeScript 编译器发现更多错误,从而减少开发人员编写的错误代码。类型保护通过提高代码的可读性和重构性,为代码创建了更完善的结构。

有兴趣了解 JavaScript 和 TypeScript 之间的更多区别吗?您可以在这里了解更多信息:JavaScript 和 TypeScript 之间有什么区别?

IDE 支持

由于 TypeScript 提供了类型,文本编辑器和集成开发环境 (IDE) 可以为开发人员提供更多有用的信息。这些环境可以提供自动完成、代码导航、错误标记等功能,从而提高团队的工作效率。

一些支持 TypeScript 3 的流行环境:

  • 微软 Visual Studio

  • WebStorm

  • Visual Studio 代码

  • 原子

浏览器兼容性

浏览器兼容性是 TypeScript 提供的强大功能之一。TypeScript 编译器会转换你的代码,使其与所有现代浏览器兼容。这种兼容性是因为编译器能够将 TypeScript 代码转换为所有设备、平台和浏览器都支持的原生 JS。

虽然使用 TypeScript 有很多优势,但它并非完美的解决方案。提升代码可读性的一个缺点是,你必须编写更多代码,这可能会增加开发时间。与使用原生 JavaScript 相比,它还会增加 TypeScript 文件的大小。

成为一名 TypeScript 开发人员。

Educative 的学习 TypeScript课程允许完全的初学者学习主要概念,从而成为一名成熟的 TypeScript 开发人员。

学习 TypeScript:初学者完整课程

您已经是 TypeScript 学习者了吗?

通过实践掌握高级概念并提高您的 TS 技能。

高级 TypeScript 大师班

严格类型简介

现在我们已经了解了 TypeScript 提供的功能,让我们深入了解一些使 TypeScript 成为强大工具的更高级的概念。

noImplicitAny

根据文档,的定义noImplicitAny是“对任何隐含类型的表达式和声明引发错误”。

这意味着,只要 TypeScript 可以推断类型,如果你允许 ,就会出现错误noImplicitAny。这个例子可以通过传递函数参数来看到。

function print(arg) {
    send(arg);
}

print("hello");
print(4);
Enter fullscreen mode Exit fullscreen mode

在上面的代码中,函数的有效参数是什么print如果你没有为函数参数添加类型,TypeScript 将为该参数分配类型any,从而关闭类型检查。

对于注重代码安全性的开发人员,可以使用,它会通知他们代码中noImplicityAny任何可能的类型。让我们看看使用相同的函数会发生什么。anyprint

function print(arg) { // Error : someArg has an implicit `any` type
    send(arg);
}
Enter fullscreen mode Exit fullscreen mode

要修复错误,您可以注释函数参数。

function print(arg: number) { // Error : someArg has an implicit `any` type
    send(arg);
}
Enter fullscreen mode Exit fullscreen mode

但如果您仍然想要类型any,您可以明确将参数标记为any

function print(arg: any) { // Error : someArg has an implicit `any` type
    send(arg);
}
Enter fullscreen mode Exit fullscreen mode

unknown

类型unknown与 类型类似,any因为所有类型都可以赋值给anyunknown类型,但区别在于 类型any可以赋值给任何其他类型,而unknown类型不可赋值给任何其他类型。这种区别可能比较容易混淆,我们来看一个例子。

function example1(arg: any) {
  const a: str = arg; // no error
  const b: num = arg; // no error
}

function example2(arg: unknown) {
  const a: str = arg; // 🔴 Type 'unknown' is not assignable to type 'string'.(2322)
  const b: num = arg; // 🔴 Type 'unknown' is not assignable to type 'number'.(2322)
}
Enter fullscreen mode Exit fullscreen mode

一个变量arg被传递给两个函数,其类型可以是stringnumber或其他类型。无论其类型是什么,arg都会被赋值给anyunknown

但是,与any类型不同,类型的变量unknown不能分配给另一种类型,如第 7 行和第 8 行所示。类型any是双向的,而unknown是单向的。

unknown当你不知道传递给函数的值的类型,但又想摆脱这些情况时,类型会很有帮助any这提高了代码的安全性,因为any类型可以传播,使你的代码库更容易出错。

strictNullChecks

在 TypeScript 中,nullundefined可以分配给每种类型,这意味着它们属于所有类型的域。

let num: number = 123;
num = null; // Okay
num = undefined; // Okay
Enter fullscreen mode Exit fullscreen mode

通常,这会导致意外错误,因为您可以对值为null或 的变量调用方法undefined

interface Person {
  hello(): void;
}

const num: number = undefined;
const str: string = null;
const person: Person = null;

person.hello(); // 🔴 Runtime Error!
Enter fullscreen mode Exit fullscreen mode

在严格空检查模式下,null和不会自动属于所有类型,因此您不能将它们用于不包含或 的undefined类型。这样,您可能会在编译时收到一条错误,提示nullundefinedObject is possibly 'undefined'

Luna是 的一个实例对象Dog

class Dog
{
    age: number
    breed: string    

    constructor(age: number, breed: string) 
    {
        this.age = age
        this.breed = string
    }    

    getRelativeAge(): number
    {
        return this.age * 7
    }
}

let Luna = new Dog(2, 'Labrador')
Enter fullscreen mode Exit fullscreen mode

此语法相当于在 JavaScript ES5 中使用函数对象。

function Dog(age, breed)
{
    this.age = age
    this.breed = breed
}

Dog.prototype.getRelativeAge = function() {
    return this.age * 7
}

var Spot = new Dog(2, 'Labrador')
Enter fullscreen mode Exit fullscreen mode

遗产

既然你已经了解了如何创建对象,那么学习 TypeScript 中的继承就很重要了。继承允许子类从其父类继承某些属性。

例如,您有Animal一个作为父类。

class Animal
{
    age: number
    breed: string    

    constructor(age: number, breed: string)
    { 
        this.age = age
        this.breed = breed
    }    

    makeSound_(sound: string): void
    {
        console.log(sound)
        console.log(sound)
        console.log(sound)
    }
}
Enter fullscreen mode Exit fullscreen mode

然后,可以创建一个Dog子类。使用关键字 可以实现基本的继承super,在子类中将其作为函数使用,调用父类中相应的函数。

class Dog extends Animal
{
    playsFetch: boolean    constructor(age: number, breed: string, playsFetch: boolean)
    {
         super(age, breed) // call parent constructor
         this.playsFetch = playsFetch
    }    makeSound(): void
    {
        super.makeSound_('woof woof')
    }    getAgeInHumanYears(): number
    {
        return this.age * 7    // super.age will throw error
    }
}
class Cat extends Animal
{
    constructor(age: number, breed: string)
    {
        super(age, breed)
    }    makeSound(): void
    {
        super.makeSound_('meow meow')
    }
}
Enter fullscreen mode Exit fullscreen mode

接口

接口在 JavaScript(以及 TypeScript)中非常强大,因为它们对运行时没有任何影响。TypeScript 允许你声明变量的结构,这赋予了你更强大的功能。

interface Point {
    x: number; y: number;
}
declare var test: Point;
Enter fullscreen mode Exit fullscreen mode

TypeScript 中的接口是开放式的,因此其他作者可以在现有的test变量声明的基础上进行构建。

interface Point {
    x: number; y: number;
}
declare var myPoint: Point;

interface Point {
    z: number;
}

var myPoint.z; // Allowed
Enter fullscreen mode Exit fullscreen mode

类还可以通过使用关键字来实现接口,以便它们遵循预定义的对象结构implements

interface Point {
    x: number; y: number;
}

class MyPoint implements Point {
    x: number; y: number; // Same as Point
}
Enter fullscreen mode Exit fullscreen mode

由于这个implements关键字,界面中的任何更改都会产生编译错误,以便您可以轻松更新代码库。

interface Point {
    x: number; y: number;
    z: number; // New member
}

class MyPoint implements Point { // ERROR : missing member `z`
    x: number; y: number;
}
Enter fullscreen mode Exit fullscreen mode

TypeScript 中的类型

TypeScript 最重要的方面之一是从现有的泛型类型创建自定义类型。

联合类型

通常,您可能希望代码允许多种数据类型。当接受nullundefined值时,这种需求尤其明显。联合类型可以解决这个问题,它由注解表示|

const hello = (name: string | undefined) => { /* ... */ };
Enter fullscreen mode Exit fullscreen mode

在此示例中,类型name定义为string | undefined,这意味着任何类型的变量name都可以是stringundefined

交叉口类型

交叉类型将多个类型组合成一个,使新类型具备组合后类型的特性。您可以通过关键字来实现extend,如下所示。

function extend<T, U>(first: T, second: U): T & U {
  return { ...first, ...second };
}

const x = extend({ a: "hello" }, { b: 42 });

// x now has both `a` and `b`
const a = x.a;
const b = x.b;
Enter fullscreen mode Exit fullscreen mode

元组类型

与 JavaScript 不同,TypeScript 提供了元组类型,它允许你表达一个具有非统一类型和固定数量元素的数组。以下示例演示了一个元组。

var nameNumber: [string, number];

// Okay
nameNumber = ['Ben', 12345];

// Error
nameNumber = ['Ben', '12345'];
Enter fullscreen mode Exit fullscreen mode

其他需要学习的主题

要成为真正的 TypeScript 大师,还有很多东西需要学习。查看这份清单,了解未来的发展方向。

  • 映射类型

  • 可区分联合类型

  • 装饰器

  • 函数类型和返回类型

  • TypeScript 中的函数式编程

  • 状态机

  • 泛型函数

总结和资源

现在您已经了解了 TypeScript 的一些高级主题,是时候开始探索更多强大的 TypeScript 功能了。查看我们的高级 TypeScript 大师班,掌握这门语言并充分利用 TypeScript 提供的工具。

完成课程后,你将对自己的 TypeScript 技能更加自信,能够编写自己的类型,轻松识别编译后的错误,甚至提升你的 JavaScript 整体知识。课程涵盖的主题包括严格类型、泛型函数、泛型接口、组合类型、常见错误等。

继续阅读有关 TypeScript 的内容

鏂囩珷鏉ユ簮锛�https://dev.to/educative/understanding-advanced-concepts-in-typescript-9bn
PREV
来自拥有 15 年以上经验的开发者对(初级)开发人员的建议 Edwin 是谁 🧐 我的职业生涯(迄今为止) 👨🏻‍💻 我给其他开发人员的建议 👨🏻‍🏫 总结 🏁
NEXT
40 个最热门的 Docker 面试问题(附答案)