作为JavaScript的“超集”,感受一下TypeScript 的那些黑魔法

管理员账号

2019-11-26

// TypeScript 是JavaScript的“超集” //

// 前端语言中冉冉升起的新星 //

TypeScript是一种由微软开发的、开源的编程语言,近两年发展迅猛,越来越多的JavaScript项目正在迁移到TypeScript,主流前端框架及Node.js对TypeScript的支持也越来越友好。自2012年10月发布首个公开版本以来,它已得到了人们的广泛认可。

TypeScript发展至今,已经成为很多大型项目的标配,其提供的静态类型系统,大大增强了代码的可读性及可维护性;同时,它提供最新的和不断发展的JavaScript特性,能让我们构建更健壮的组件。

然而在TypeScript中,有些地方对“开箱即用”进行了限制,例如当使用一个未被声明过的变量时(当然,你可以为外部系统使用声明文件)。也就是说,传统的编程语言在类型系统允许与不允许之间存在明显的边界。

TypeScript不同于传统的编程语言,它可以让你自己设置类型系统的边界。这实际上是为了让你能够使用你喜欢的JavaScript,并尽可能安全地使用它。

在TypeScript中,有很多选项都可以精确地控制此边界,下文选自《深入理解TypeScript》一书,现在就让我们去了解它们吧。

选项为boolean的compilerOptions,可以被指定为tsconfig.json下的compilerOptions。

{
    "compilerOptions": {
        "someBooleanOption": true
    }
}

或者使用命令行。

tsc --someBooleanOption

所有这些选项的默认设置都是false。

有些代码无法被推断,或者推断它们可能会导致意外的错误。一个很好的例子就是函数参数,如果没有对它们进行注解,那么你将不清楚哪些是有效的。

functionlog(someArg) {
    sendDataToServer(someArg);
}
// 参数是什么,下面哪个是不正确的
log(123);
log('hello world');

因此,如果你没有注解函数的参数,TypeScript将会认为它是any类型的,并将继续执行。在这种情况下,将会关闭类型检查,这是JavaScript开发人员所期望的。但是这可能会让那些对安全性要求较高的人措手不及。因此,这里有一个noImplicitAny选项,当开启这个选项时,它将会标记无法被推断的类型的情况,如下所示。

functionlog(someArg) {// 错误:someArg是any类型的
    sendDataToServer(someArg);
}

当然,你可以继续进行注解。

functionlog(someArg: number) {
    sendDataToServer(someArg);
}

如果真的想抛弃安全性,你可以把它标记为any。

functionlog(someArg: any) {
    sendDataToServer(someArg);
}

在默认情况下,null和undefined可以被赋值给TypeScript中的所有类型。

let foo: number = 123;
foo = null;        // 可以
foo = undefined; // 可以

这顺应了大多数编写JavaScript的人的习惯。但是,同时TypeScript允许你明确指出可以分配给null/undefined的内容。

在严格的null检查模式下,null和undefined是不同的。

let foo = undefined;
foo = null;        // 不可以

假设有一个接口Member,如下所示。

interface Member {
    name: string,
    age?: number
}

并不是所有的Member都会提供年龄,所以age是一个可选属性,也就是说age的值可能为undefined。

undefined是“万恶之源”,它通常会导致运行时错误。(编写在运行时抛出错误的代码很容易。)

getMember()
    .then(member: Member =>{
        conststringifyAge = member.age.toString()

            //toString属性可能undefined
})

但是在严格的null检查模式下,这个错误将会在编译时被捕获。

getMember()
    .then(member: Member =>{
    conststringifyAge = member.age.toString() // 对象可能undefined
})

◆ 非空断言操作符

在一个类型检查无法得出结论的上下文中,一个新的!表达式后缀操作符,可以用来断言运算对象是非null和非undefined的,示例如下。

  // 用--strictNullChecks进行编译
functionvalidateEntity(e?:  Entity) {
 // 如果e是null或其他无效的实体,则抛出错误
 }

functionprocessEntity(e?: Entity) {
    validateEntity(e);
    let a = e.name;        // 错误:e可能是null
    let b = e!.name;       // 可以,我们已经断言e是非null
}

注意,它只是一个断言,就像类型断言一样,你需要确保该值不为空。一个非null的断言实质上意味着你在告诉编译器“我知道它不是null,但是请让我使用它,即使它不是null”。

◆ 明确赋值断言操作符

TypeScript将会对类中未初始化的属性抛出错误。

class C {
foo: number;                  // 可以,已经在构造器中初始化
bar: string = "hello";      // 可以,已经初始化
baz: boolean;               

// 错误:属性baz没有初始化,也没有在构造器中被赋值
    constructor() {
        this.foo = 42;
    }
}

你可以使用明确赋值断言,在属性名后加后缀,来告诉TypeScript你已经在其他地方(不是在构造器中)对它进行了初始化。

class C {
    foo!: number;           // 注意这个感叹号
            // 这是明确赋值断言操作符

    constructor() {
        this.initialize();
    }
    initialize() {
        this.foo = 0;
    }
}

你也可以将此操作符与变量声明一起使用。

你也可以将此操作符与变量声明一起使用。

let a: number[];           // 没有断言
let b!: number[];             // 断言

initialize();

a.push(4);                   // 错误:变量在赋值之前被使用
b.push(4);                   // 可以:因为被断言

functioninitialize() {
    a = [0,1,2,3];
    b = [0,1,2,3];
}

就像所有的断言一样,你在告诉编译器让它相信你,让编译器不再抛出错误,即使代码并没有被分配属性。

作为JavaScript的“超集”,TypeScript静态类型检查让我们能轻松地构建和维护大型的前端项目。《深入理解TypeScript》一书是 TypeScript Deep Dive 的中文版,全面阐述了TypeScript的各种“魔法”,示例丰富,简单易懂,并且对初学者非常友好!

本书从实际应用场景出发,对TypeScript语言进行深度剖析,并结合代码示例讲解了诸多TypeScript高级编程技巧,以及在实际开发工作中的最佳实践方案,能帮助读者更加透彻地理解TypeScript。

█ 与官方文档相比,本书主要有以下几个特点

1.知识点全面。本书不仅涵盖了官方文档的大部分知识点,对于官方文档中没有却经常遇到的知识点,也做了细致的讲解。

2.示例丰富,简单易懂。书中的例子,大都来自作者对日常工作的总结,我们甚至可以直接将它们用于自己的开发工作。

3.深入编译原理。在与TypeScript编译原理相关的章节中,本书对如何把TypeScript编译为JavaScript做了详尽的解析。

█ 关 于 作 译 者

Basarat Ali Syed

TypeScript专家,微软JavaScript/TypeScript的MVP贡献者。他是TypeScript社区受人尊敬的成员,澳洲Picnic software高级开发人员,在DefinitelyTyped团队工作。Basarat经常参加澳大利亚与前端开发技术有关的会议,在多个技术活动中做过演讲。Basarat还著有Beginning Node.js 一书,目前该书已被下载39000多次,在亚马逊、豆瓣等平台得到了读者的一致好评。

郭文超:TypeScript深度爱好者,常用笔名三毛,公众号 FENews 主要维护者。曾在 TutorABC、eBay 任职,目前在千寻位置担任前端工程师。对 TypeScript、React、Vue 等有较深理解。

何小磊:山西能快科贸CTO,有十年以上软件开发经验。

柳星:TypeScript 重度用户,常用网名 S1ngS1ng,是 freeCodeCamp 中文社区的维护者之一。曾在 Rackspace、VMware、Apple 任前端工程师一职。

徐野:携程AI研发部前端工程师。热爱大前端,爱折腾新鲜技术,精通 TypeScript、React、Node 等前端技术。

█ 目 录 结 构

第1章 为什么要使用TypeScript

第2章 JavaScript常见语法

第3章 JavaScript 新语法特性

第4章 TypeScript项目构成

第5章 快速创建TypeScript项目

第6章 TypeScript类型系统

第7章 关于 JSX

第8章 TypeScript编译选项设置

第9章 TypeScript错误处理

第10章 开发与测试工具

第11章 提示与建议

第12章 TypeScript代码风格指南与代码约定

第13章 TypeScript编译原理

读者评论

相关博文

  • 社区使用反馈专区

    陈晓猛 2016-10-04

    尊敬的博文视点用户您好: 欢迎您访问本站,您在本站点访问过程中遇到任何问题,均可以在本页留言,我们会根据您的意见和建议,对网站进行不断的优化和改进,给您带来更好的访问体验! 同时,您被采纳的意见和建议,管理员也会赠送您相应的积分...

    陈晓猛 2016-10-04
    3556 596 3 6
  • 迎战“双12”!《Unity3D实战核心技术详解》独家预售开启!

    陈晓猛 2016-12-05

    时隔一周,让大家时刻挂念的《Unity3D实战核心技术详解》终于开放预售啦! 这本书不仅满足了很多年轻人的学习欲望,并且与实际开发相结合,能够解决工作中真实遇到的问题。预售期间优惠多多,实在不容错过! Unity 3D实战核心技术详解 ...

    陈晓猛 2016-12-05
    2289 34 0 1
  • czk 2017-07-29
    2818 21 0 0