基本数据类型
状态: 初稿
介绍
我们的程序需要存储和处理数据, 而所有复杂数据结构都是由数字, 字符串, 结构, 布尔类型等基本单元组合而成的.
TypeScript 不仅包含几乎所有你期望在 JavaScript 见到的那些基本数据类型, 还新增了枚举类型帮助你写出更可读的程序. 本文将介绍它们.
布尔类型(Boolean)
布尔类型(Boolean), 你只能用它表示两个值——真(true
), 假(false
). 用关键字 boolean
来定义一个布尔类型的变量.
1 | let isDone: boolean = false; |
数字类型(Number)
数字类型(Number). 跟 JavaScript 一致, 所有 TypeScript 中的数字都是浮点数.
我们用 number
关键字来定义数字型变量.
从 ECMAScript 2015 开始, TypeScript 同时支持十进制, 十六进制, 二进制, 和八进制字面量.
以下都是对一个 number
变量的正确初始化.
1 | let decimal: number = 6; |
字符串(String)
无论是创建网页还是类服务端(servers alike)应用, 字符串(String, 或文本类型)都是另一种重要的数据类型.
我们用关键字 string
来定义一个字符串变量.
字符串字面量必须以成对的单引号 (‘) 或双引号 (“) 环绕.
1 | let color: string = "blue"; |
模板字符串(template strings)能够在源程序中跨越多行. 它们以反引号 (`) 环绕;
你还可以在模板字符串内嵌入表达式, 这些表达式形如: ${ expr }
1 | let fullName: string = `Bob Bobbington`; |
以上对 sentence
的定义等同于:
1 | let sentence: string = "Hello, my name is " + fullName + ".\n\n" + |
数组(Array)
数组(Array)存储相同类型的一组元素.
有两种描述数组类型的方式:
其一, 在元素类型后面加一对方括号([])将其扩展为存储该类型的数组类型:
1 | let list: number[] = [1, 2, 3]; |
其二, 特化泛型数组类型 Array<elemType>
.
译注: 参考泛型一章.
1 | let list: Array<number> = [1, 2, 3]; |
元组(Tuple)
元组(Tuple)类似数组, 但有几个不同点:
- 数组的长度是可变的, 元组长度不可变;
- 数组中的元素类型一致, 元组的每个元素类型可以不同.
以下定义表示一个 string
值, 一个 number
值的二元组:
1 | // Declare a tuple type |
你可以用下标访问元组中位于不同位置的元素, 该表达式值的类型是取得的元素类型:
1 | console.log(x[0].substring(1)); // OK |
访问不存在的下标引发程序错误:
1 | x[3] = "world"; // Error, Property '3' does not exist on type '[string, number]'. |
枚举(Enum)
枚举类型(Enum)是一项对标准 JavaScript 很有用的补充.
我们知道, C# 等支持枚举的语言能够赋予一组数字好记的名字.
1 | enum Color {Red, Green, Blue} |
枚举元素的值默认从 0
开始依次递增.
你也可以手动为一个元素指定值, 它后面元素的值继续在它的基础上递增.
下例, 我们让枚举 Color
从 1
开始:
1 | enum Color {Red = 1, Green, Blue} |
你还可以手动为所有枚举元素指定它代表的数值.
1 | enum Color {Red = 1, Green = 2, Blue = 4} |
一个方便的特性是反向查询 — 查询数值在一个枚举集合中对应的枚举成员名.
比如, 我们不知道数值 2
代表 Color
枚举集合中的哪个成员, 可借助反向查询语法:
1 | enum Color {Red = 1, Green, Blue} |
Any
有时, 我们暂不能确定一个变量将要存储什么类型的值.
它的值可能来自动态内容(dynamic content), 比如用户, 第三方库.
针对这种情况, 我们把它的类型设为 any
.
以表明不希望这个变量参与静态类型检查, 直接通过编译:
1 | let notSure: any = 4; |
any
是一条用于沿用现有 JavaScript 的强大途径, 它允许你逐步引入和移除编译期类型检查.
有人认为它等同于其他语言的 Object
.
然而, 这并不准确, 虽然你可以把任何变量赋值给一个 Object
, 但你不能在这个引用上任意调用原变量的方法, 即使这些方法的确存在:
1 | let notSure: any = 4; |
注: 如同在我们 Do’s and Don’ts 一章描述的, 避免像使用原始类型
object
那样使用Object
.
假如你仅了解一个类型的一部分 — 而不是所有, any
也能带来方便.
比如说, 你有一个元组 (译注: 原文是数组), 它的元素类型不尽相同.
1 | let list: any[] = [1, true, "free"]; |
Void
你可以按 any
的相反面来理解 void
: 不存在任何类型.
通常, 你会看到这个关键字作为函数的返回值类型出现, 表明这个函数不返回值.
1 | function warnUser(): void { |
定义 void
类型的变量不见得特别有用, 因为你只能把 null
值(在没指定 --strictNullChecks
选项的前提下, 参见下节)或 undefined
值赋给它.
1 | let unusable: void = undefined; |
Null 和 Undefined
null
和 undefined
不仅都是特殊值, 它们对应的类型名也是 null
和 undefined
.
同 void
, 我们一般不单独定义 null
和 undefined
类型的变量.
1 | // Not much else we can assign to these variables! |
通常, null
和 undefined
是其他所有类型的子类型.
这意味着你可以把 null
值或 undefined
值赋值给 number
等变量.
但是, 当 --strictNullChecks
选项打开后, null
和 undefined
就只能赋值给 any
和它们自身的类型了, 即 null
和 undefined
(例外之一是 undefined
还可以赋值给 void
).
该选项能够消除许多常见错误.
如果你确实希望随时把 string
, null
, 或 undefined
之一赋值给同一个变量, 你可以把这个变量定义为 string
, null
和 undefined
的联合: string | null | undefined
.
我们在以后的章节重点探讨联合数据类型.
注: 我们鼓励打开
--strictNullChecks
, 但是在这本手册中, 我们假定它是关闭的.
Never
never
表示永远不会产生值.
例如: 如果一个函数表达式或箭头函数表达式始终抛出异常, 或从不返回, 它的返回值类型就是 never
;
1 | // Function returning never must have unreachable end point |
又如: 一个变量 x
属于类型护卫永不为真的那一分支, 它的类型也是 never
.
译注: 类型护卫首次出现在高级数据类型一章.
1 | function narrowByTypeGuard(x: number | string) { |
never
是其他所有类型的子类型(可赋值给所有类型); 同时, 没有类型是 never
的子类型, 因此, 任何除 never
外的值都不可以赋值给一个 never
, 包括 any
.
Object
object
可以表示任何非原始数据类型(任何除 number
, string
, boolean
, symbol
, null
, 和 undefined
外的).
有了 object
, 我们能更好地表达形如 Object.create
的方法:
1 | declare function create(o: object | null): void; |
类型担保
有时, 你可能比 TypeScript 更了解一个值.
特别地, 当你知道一个值的实际类型比它当前类型(译注: 引用它的变量类型是该值的父类型)更具体时.
类型担保打开了与编译器协商的通道: “相信我, 我知道我在干什么. ”
类型担保类似其他语言的强制类型转换, 但它既不重组数据(restructuring), 又不做任何运行时检查.
换言之, 它完全在编译期实现, 不加重运行期负担.
如果你使用类型担保, TypeScript 假定你 — 作为编程人员, 已经做了必要的检查.
有两种类型担保形式.
其一, 尖括号式:
1 | let someValue: any = "this is a string"; |
其二, as 关键字式:
1 | let someValue: any = "this is a string"; |
以上两种写法完全等同.
一般, 选择哪种取决于个人偏好. 但当你结合 TypeScript, JSX 使用时, 只有 as 关键字式是有效的.
关于 let
到目前为止, 我们一直用 let
关键字代替或许你更熟悉的 var
.
ES2015 为 JavaScript 引入 let
关键字, 它比 var
更安全, 所以正在逐渐成为标准写法.
我们以后再讨论其细节, 建议你尽可能用 let
代替 var
, 它能减轻很多常见 JavaScript 问题.