TypeScript入门完全指南(基础篇)

本文来源于团队内分享。TypeScript的官方文档虽然较为全面,但通读下来却要耗时不少;另外,TypeScript中文资料本身也比较缺乏,本文可作为准备尝试TypeScript的同学入门使用,涵盖了上手TypeScript之前所需要的所有基础知识。

为什么JS需要类型检查

TypeScript的设计目标在这里可以查看到,简单概括为两点:

  1. 为JavaScript提供一个可选择的类型检查系统;
  2. 为JavaScript提供一个包含将来新特性的版本。

TypeScript的核心价值体现在第一点,第二点可以认为是TypeScript的向后兼容性保证,也是TypeScript必须要做到的。

那么为什么JS需要做静态类型检查呢?在几年前这个问题也许还会存在比较大的争议,在前端日趋复杂的今天,经过像Google、Microsoft、FaceBook这样的大公司实践表明,类型检查对于代码可维护性和可读性是有非常大的帮助的,尤其针对于需要长期维护的规模性系统。

TypeScript优势

在我看来,TypeScript能够带来最直观上的好处有三点:

  1. 帮助更好地重构代码;
  2. 类型声明本身是最好查阅的文档。
  3. 编辑器的智能提示更加友好。

一个好的代码习惯是时常对自己写过的代码进行小的重构,让代码往更可维护的方向去发展。然而对于已经上线的业务代码,往往测试覆盖率不会很高,当我们想要重构时,经常会担心自己的改动会产生各种不可预知的bug。哪怕是一个小的重命名,也有可能照顾不到所有的调用处造成问题。

如果是一个TypeScript项目,这种担心就会大大降低,我们可以依赖于TypeScript的静态检查特性帮助找出一个小的改动(如重命名)带来的其他模块的问题,甚至对于模块文件来说,我们可以直接借助编辑器的能力进行“一键重命名”操作。

另外一个问题,如果你接手过一个老项目,肯定会头痛于各种文档的缺失和几乎没有注释的代码,一个好的TypeScript项目,是可以做到代码即文档的,通过声明文件我们可以很好地看出各个字段的含义以及哪些是前端必须字段:

// 砍价用户信息
export interface BargainJoinData {
  curr_price: number; // 当前价
  curr_ts: number; // 当前时间
  init_ts: number; // 创建时间
  is_bottom_price: number; // 砍到底价
}
复制代码

TypeScript对开发者是友好的

TypeScript在设计之初,就确定了他们的目标并不是要做多么严格完备的类型强校验系统,而是能够更好地兼容JS,更贴合JS开发者的开发习惯。可以说这是MS的商业战略,也是TS能够成功的关键性因素之一。它对JS的兼容性主要表现为以下三个方面:

隐式的类型推断

var foo = 123;
foo = "456"; // Error: cannot assign `string` to `number`
复制代码

当我们对一个变量或函数等进行赋值时,TypeScript能够自动推断类型赋予变量,TypeScript背后有非常强大的自推断算法帮助识别类型,这个特性无疑可以帮助我们简化一些声明,不必像强类型的语言那样处处是声明,也可以让我们看代码时更加轻松。

结构化的类型

TypeScript旨在让JS开发者更简单地上手,因此将类型设计为“结构化”(Structural)的而非“名义式”(Nominal)的。

什么意思呢?意味着TypeScript的类型并不根据定义的名字绑定,只要是形似的类型,不管名称相不相同,都可以作为兼容类型(这很像所谓的duck typing),也就是说,下面的代码在TypeScript中是完全合法的:

class Foo { method(input: string) { /* ... */ } }
class Bar { method(input: string) { /* ... */ } }
let test: Foo = new Bar(); // no Error!
复制代码

这样实际上可以做到类型的最大化复用,只要形似,对于开发者也是最好理解的。(当然对于这个示例最好的做法是抽出一个公共的interface)

知名的JS库支持

TypeScript有强大的DefinitelyTyped社区支持,目前类型声明文件基本上已经覆盖了90%以上的常用JS库,在编写代码时我们的提示是非常友好的,也能做到安全的类型检查。(在使用第三方库时,可以现在这个项目中检索一下有没有该库的TS声明,直接引入即可)

回顾两个基础知识

在进入正式的TS类型介绍之前,让我们先回顾一下JS的两个基础:

相等性判断

我们都知道,在JS里,两个等号的判断会进行隐式的类型转换,如:

console.log(5 == "5"); // true 
console.log(0 == ""); // true
复制代码

在TS中,因为有了类型声明,因此这两个结果在TS的类型系统中恒为false,因此会有报错:

This condition will always return 'false' since the types '5' and '"5"' have no overlap.
复制代码

所以在代码层面,一方面我们要避免这样两个不同类型的比较,另一方面使用全等来代替两个等号,保证在编译期和运行期具有相同的语义。

对于TypeScript而言,只有nullundefined的隐式转换是合理的:

console.log(undefined == undefined); // true
console.log(null == undefined); // true
console.log(0 == undefined); // false
console.log('' == undefined); // false
console.log(false == undefined); // false
复制代码

类(Class)

对于ES6的Class,我们本身已经很熟悉了,值得一提的是,目前对于类的静态属性、成员属性等有一个提案——proposal-class-fields已经进入了Stage3,这个提案包含了很多东西,主要是类的静态属性、成员属性、公有属性和私有属性。其中,私有属性的提案在社区内引起了非常大的争议,由于它的丑陋和怪异遭受各路人马的抨击,现TC39委员会已决定重新思考该提案。

现在让我们来看看TypeScript对属性访问控制的情况:

可访问性 public protected private
类本身
子类
类的实例

可以看到,TS中的类成员访问和其他语言非常类似:

class FooBase {
    public x: number;
    private y: number;
    protected z: number;
}
复制代码

对于类的成员构造函数初始化,TS提供了一个简单的声明方式:

class Foo {
    constructor(public x:number) {
    }
}
复制代码

这段代码和下面是等同的:

class Foo {
    x: number;
    constructor(x:number) {
        this.x = x;
    }
}
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值