基本类型
学习 TypeScript 的基础知识以及如何定义简单类型
TypeScript 简介
现在你已经对 2019 年的 JavaScript 有了清晰的认识,是时候带你了解 TypeScript 了。
尽管对于 JavaScript 开发者来说,掌握 TypeScript 并非必需,但我认为它非常有用,尤其是在团队协作开发大型项目时。
正如你所知,JavaScript 不是一种强类型语言,这意味着你在声明变量时无需定义其类型。
这使得变量更加灵活,可以接受不同的值。但同时,这也可能让代码变得混乱,并更容易出现错误。
来看一个例子:
1function getUserByID(userID){ 2 // 向服务器发起 API 调用,根据 ID 获取用户信息 3}
这里的 userID 是什么类型?是整数还是字符串?我们可能会假设它是整数,但也可能是字母数字字符串(例如:'A123')。
除非你自己写了这段代码,否则根本无法确定参数的类型。
这时,TypeScript 就派上用场了。同样的代码在 TypeScript 中会这样写:
1function getUserByID(userID: number){ 2 // 向服务器发起 API 调用,根据 ID 获取用户信息 3}
完美!现在我们可以确信,如果传入的是字符串,就会引发错误。
仅仅添加了一个类型注解,就让代码更易用、更安全。
什么是 TypeScript?
由微软在几年前创建,TypeScript 是 JavaScript 的一个带有类型的超集,最终会被编译成普通的 JavaScript。
所谓“超集”意味着你可以在 TypeScript 文件中编写纯 JavaScript 代码,而不会报错。
浏览器并不理解 TypeScript,因此必须将其转换为普通的 JavaScript 才能运行。
接下来我们看看如何搭建环境来编写 TypeScript 代码。
如何使用 TypeScript
开始使用 TypeScript 只需不到 5 分钟。
第一步是安装它。在终端中运行以下命令:
npm install -g typescript
接下来,打开你的代码编辑器,创建一个名为 greeter.ts 的文件(注意不是 .js)。
1const greeter = (name: string) => { 2 console.log(`hello ${name}`) 3} 4greeter('Alberto'); 5// hello Alberto
现在,要生成对应的 JavaScript 文件,只需在终端中运行以下命令(确保当前目录包含该文件):
tsc greeter.ts
此时你应该会得到一个名为 greeter.js 的文件,内容如下:
1var greeter = function (name) { 2 console.log("hello " + name); 3}; 4greeter('Alberto'); 5// hello Alberto
name: string 这个类型声明去哪儿了?因为 JavaScript 本身不是强类型语言,所以在编译过程中,类型声明会被移除。
虽然添加类型注解不会改变最终生成的 JavaScript 代码,但它能帮助你更好地调试和减少错误。
TypeScript 基本类型
本节将介绍 TypeScript 支持的基本类型。大多数你已经在《JavaScript 入门》部分学过。
TypeScript 支持的基本类型包括:
booleannumberstringArrayobjectTupleenumanyvoidnull与undefinednever
boolean
表示布尔值,只能是 true 或 false:
1const active: boolean = true;
number
number 类型支持十六进制、十进制、二进制和八进制字面量:
1const decimal: number = 9; 2const hex: number = 0xf00d; 3const binary: number = 0b1010; 4const octal: number = 0o744;
string
string 类型用于存储文本数据:
1const message: string = 'Welcome';
Array
定义数组类型有两种方式:
1// 第一种方式 -> 类型[] 2const firstArray: number[] = [1, 2, 3]; 3 4// 第二种方式 -> Array<类型> 5const secondArray: Array<number> = [4, 5, 6];
在简单场景下两者没有区别。但如果处理的是复杂类型,第一种写法就无法使用了。
比如这个例子:
1// 函数接收一个对象数组,每个对象包含 label 和 value 属性 2function example(arg: Array<{label: string, value: string}>) { 3 // 做一些事情 4}
Array<{label: string, value: string}> 表示参数是一个包含两个字符串属性的对象数组。
object
object 类型表示非原始类型的数据,即不是 number、string、boolean 等基本类型。
假设我们的函数接收一个 object 类型的参数:
1function greetUser(user: object){ 2 // 属性 name 在类型 object 上不存在 3 console.log(`hello ${user.name}`) 4} 5greetUser({name: 'Alberto', age: 27}); 6// hello Alberto
TypeScript 编译器会报错,指出 name 属性在 object 类型上不存在。
我们需要更精确地定义对象结构:
1function greetUser(user: {name: string, age: number}){ 2 console.log(`hello ${user.name}`) 3} 4 5greetUser({name: 'Alberto', age: 27}); 6// hello Alberto
现在我们明确指定了用户对象的所有属性,这让代码更清晰,也方便其他人理解这个对象可以做什么、不能做什么。
Tuple
Tuple 用于定义数组中已知元素的具体类型。
1let myTuple: [string, number, string]; 2myTuple = ['hi', 5, 'hello']; 3 4console.log(myTuple); 5// [ 'hi', 5, 'hello' ]
TypeScript 会知道元组中各个索引位置的类型,但无法推断后续新增元素的类型。
enum
enum 是为一组数值赋予名称的方式。
1enum Status { deleted, pending, active } 2 3const blogPostStatus: Status = Status.active; 4 5console.log(blogPostStatus); 6// 2
枚举中的值从 0 开始编号,因此在这个例子中:
deleted对应 0pending对应 1active对应 2
说状态是 active 比说它是 2 更有意义。
你也可以自定义起始值:
1enum Status { deleted = -1, pending, active } 2 3const blogPostStatus: Status = Status.active; 4console.log(blogPostStatus); 5// 1
此时:
deleted为 -1pending为 0active为 1
更好理解了。
你还可以通过值反查枚举名:
1enum Status { deleted = -1, pending, active } 2console.log(Status[0]); 3// pending
any
顾名思义,any 表示变量可以是任意类型。
当你使用不支持 TypeScript 的第三方库,或正在将现有 JavaScript 代码迁移到 TypeScript 时,可能会用到 any。
使用 any 可以访问可能不存在的属性和方法。
你也可以在只知道部分类型的情况下使用 any:
1let firstUser: Object<any> = { 2 name: 'Alberto', 3 age: 27 4} 5 6let secondUser: Object<any> = { 7 name: 'Caroline' 8}
我们期望这两个变量都是对象类型,但不确定它们的具体属性,因此使用 any。
void
void 表示“无类型”,通常用于函数没有返回值的情况。
1function storeValueInDatabase(objectToStore): void { 2 // 将数据存入数据库 3}
这个函数接收一个对象并保存到数据库,但不返回任何值,所以返回类型设为 void。
声明 void 类型的变量时,只能赋值为 null 或 undefined。
null 与 undefined
与 void 类似,直接声明 null 或 undefined 类型的变量意义不大,因为只能赋值为自身。
但在学习“联合类型”时,你会看到它们的实际用途。
never
never 表示永远不会发生的值。常用于永远不返回或总是抛出异常的函数。
1function throwError(error: string): never { 2 throw new Error(error); 3}
这个函数只会抛出错误,永远不会返回任何值。
下一课我们将学习接口和类。