Logo
Section 1 / 4

基本类型

学习 TypeScript 的基础知识以及如何定义简单类型

导入

基本类型

学习 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 支持的基本类型包括:

  • boolean
  • number
  • string
  • Array
  • object
  • Tuple
  • enum
  • any
  • void
  • null 与 undefined
  • never

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 对应 0
  • pending 对应 1
  • active 对应 2

说状态是 active 比说它是 2 更有意义。

你也可以自定义起始值:

1enum Status { deleted = -1, pending, active } 2 3const blogPostStatus: Status = Status.active; 4console.log(blogPostStatus); 5// 1

此时:

  • deleted 为 -1
  • pending 为 0
  • active 为 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}

这个函数只会抛出错误,永远不会返回任何值。

下一课我们将学习接口和类。

从 ES2016 到 ES2022

接口、类与更多内容