这是我参与「第四届青训营」笔记创作活动的的第2天。
结合今日的青训营课程,本文旨在让读者快速入门TypeScript(简称TS),以及介绍TS细节上的坑。下一篇将着重介绍几个常见的坑。
阅读本文你将获得以下知识:
- 什么是动/静态类型
- 什么是强/弱类型的语言
- 上手TypeScript
- TypeScript新类型简介
TypeScript入门前简介
如其名所示,TypeScript加强了JavaScript中变量类型,使其成为静态类型。
注意是变量的类型。在JS中,变量的类型是动态的。这意味着JS编译前无法确定变量的类型,但需注意,即使是在JS中,字面量如'Hello World'是静态类型,是编译前可知的,为String。而let a = 'Hello World',则a在编译前类型不知,只有在执行时才可知为String。
因此TypeScript只是将动态类型转为静态类型,TypeScript本身仍并非强类型语言,而是和JavaScript一道,都是弱类型语言。如果读者先前有学习过传统的编程语言,像C/C++、Java甚至Python等都是常见的强类型语言。
强/弱类型语言的区别在于变量类型的隐式转换。弱类型如JS、TS,允许在执行过程中隐式地改变变量的类型。
比如,在js中,我们要将一个数字转成字符串,只需:
let a = 1 + "";
console.log(typeof a); // string
console.log(a); // 1
而如果是在C/C++中,则常需要借助的sprintf()函数等来将其转化为字符串。
基本语法
类型声明
number、string、数组
let a : number = 1;
let s : string = 'Hi';
let arr : any[] = [a, s];
console.log(arr); // [1, 'Hi'];
let numArrA : number[] = [1,2,3]; // 两种数组声明方式
let numArrB : Array<number> = [4,5,6];
类型别名与接口
类型别名可以方便地定义对象的必填、选填项。
type Person {
name: string; // 必填
age?: number; // 选填
}
let newPerson : Person = {name: 'RHXIE'};
// ✅age可不填,不报错
当一个对象里所包含的属性较为复杂,有必填的、选填的、只读属性、约束任意额外属性的等等,如下所示
interface Person {
name: string; // 必填
age?: number; // 选填
readonly id: string; // 只读,初始化后不能更改
[key: string]: string | number | object | undefined;
// 限制整个接口中可使用的所有类型
}
let me: Person = {
// name : 'RHXIE';
// ⛔不填name报错:此为必填项
id: "114514", // ✅允许
others: {}, // ✅允许
married : false // ⛔报错,上面没允许boolean类型
};
me.id = '1919810'; //⛔ 报错,me.id只读
联合类型("|")和交叉类型("&")
很好理解,在数学里叫“并集”与“交集”,计算机里的“或”和“与”
如let a : string | number,a既可以是string也可以是number,表示“或”的关系。
如果是常量,如let b : 'male' | 'female',则表示b是string类,且值只能取'male'或'female'
而&表示“与”的关系,在类型别名和接口中会用得到:
type Book {
author : string;
} & ( {
tag: 'history'; //
range: string; // 历史书籍的往往会有一个历史范围
} | {
tag: 'novel';
theme: string; // 而小说往往会有一个主题
} )
}
这样一来,如果tag是history,则会有range属性;反之如果tag是novel,则会有theme属性,而不会有range属性。其中“&”可以理解为“并集”,选择&后一个集合中的所有属性,添加到Book中。
使用TypeScript你需要了解的类型
已经在JS里出现过的不再赘述,以下是几个基础的常见TypeScript类型:
- any
- unknown
- void
- never
- tuple
- enum
* 现阶段建议先了解,还不需要深入,
我们逐个介绍:
- any。当在TS中不声明变量的类型时,你常常会见到这个词出现在你眼前。意思是变量可以为任何类型,与原生JS几乎没有区别。
但初学者不建议使用any。有人笑称人写的不是TypeScript而是AnyScript,并不稀奇。如果你现在手上有几个之前写的.html,简单将里面的JS转成TS,就发现需要重新声明一大堆变量的类型。虽然大多数都是number string Array,但一旦遇到不好确定的类型(复合类型)、不好解决的TS报错,塞个any也能完事。如果是参与项目开发,这样对项目的后续维护会造成困难,许多原本可以避免的bug将层出不穷。
当然,对于写一次就扔的TS,比如学校的作业啊,简单的playground啊,也没问题,甚至直接拿JS写更快。
如果认真地解决了TypeScript提示的错误,不仅对你认识TypeScript有帮助,而且也可以回过头来让你熟悉一下之前HTML、JS没有接触到的内容。这个具体之后会以例子提到。
- unknown
类似any,区别是不能随便赋值,只能再赋给unknown类型的变量。比如下面就报错
let u : unknown = 'Hello';
let s : string = 'The World!';
s = u; // Type 'Unknown' is not assignable to type 'string'
相当于是一个有类型安全的any,没有与其他类型隐式转换的方式。但赋值给同为unknown的变量是可以的,
- void
在强类型语言里很常见。一般用于声明函数不返回除了null和undefined之外的任何值。
- never
简而言之用于报错的函数(如throw new Error("ERROR")),函数不返回任何值。
- tuple
元组,在Python里很常用,表示长度不变的向量。
- enum
枚举类型,用于添加一类常量,提高代码可读性,比如:
enum Job {
FRONT_END = 0,
BACK_END = 1,
SDET = 2,
QA = 3
}
PeopleArray.push({name: 'RHXIE', job: Job.BACK_END})
// 而如果只用0 1 2 3来代替Job里的各个枚举,可读性就稍差
TypeScript官方列了一个表,可以参考上面提到一些类型的赋值情况(颜色暂时无法画出来,建议查看官网,绿色的代表需要关掉strictNullChecks):链接
| any | unknown | object | void | undefined | null | never | |
|---|---|---|---|---|---|---|---|
| any → | ✓ | ✓ | ✓ | ✓ | ✓ | ✕ | |
| unknown → | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | |
| object → | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | |
| void → | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | |
| undefined → | ✓ | ✓ | ✓ | ✓ | ✓ | ✕ | |
| null → | ✓ | ✓ | ✓ | ✓ | ✓ | ✕ | |
| never → | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
结语
以上,是新手入门TypeScript需要了解的东西。往后还会有高级的内容如类继承、Record等等。
从JavaScript入门过渡到TypeScript其实是非常友善的过程,因为TypeScript提供了any类型,允许在.ts中完全使用JS语法写下去,即使有相关报错也是能够编译执行的。而TypeScript提供的类型提高了代码的可读性,也提高了代码的稳定性。