TypeScript基础类型总结

921 阅读9分钟

近期正在学习TypeScript,正好总结一下学习的知识点,便于自己和读者记忆。 官方文档是入门的好途径,中文文档也翻译的很详细,建议打算学习TypeScript的小伙伴先入手官方文档:www.tslang.cn/docs/handbo…

TypeScript的类型系统完全包含了JavaScript的类型系统,其中又新增了一些类型便于开发,后文我将会把TypeScript的所有基础类型一一介绍。但在介绍这些类型之前,我需要先举例让一些还没接触过TypeScript的小伙伴先了解一下通过TypeScript的基础类型来变量变量或者常量。

先来看下这几个例子:

// javascript
let hasFinished = false
let myAge = 25
let myName = '马克豚'
let myHobby = ['打篮球', '打游戏', '看书']

// typescript
let hasNotFinished: boolean = true
let yourAge: number = 18
let yourName: string = 'good reader'
let yourHobby: string[] = ['爱好一', '爱好二', '爱好三']

通过上面的例子,聪明的读者们应该已经发现TypeScriptJavaScript在定义变量写法上的一些不同。但实际上上面两种写法在TypeScript是等价的,因为TypeScript会根据变量的初始值自动推断出变量的类型,所以这种情况下也可以不指定变量的类型,但值得注意的是类型一旦确定是不允许改变的(eg: yourAge = '18'不被允许)。 再说到两种写法的不同之处,细心的读者可以发现,在TypeScript定义变量时,在变量名后面指定变量的类型,写法为:

变量名: 变量类型

熟悉Java的同学可能知道,在java中定义变量同样需要指定变量类型,不过类型名是定义在变量名之前的,我们可以把TypeScript的这种定义方法称为类型后置,即类型定义在变量名称之后。 注意:类型后置这种说法并不是官方说法,纯属我个人为了便于记忆加以修饰的做法,不习惯的读者可以不做理会。

上面说了那么多,我现在正式开始一一介绍TypeScript的基础类型。

布尔类型(Boolean)

TypeScript的布尔类型,只具有true、false两个可选值。

let hasNotFinished: boolean = true

由于TypeScript本身会根据变量的初始值推断出变量的类型,所以下面的代码也能达到同样的效果。但是我还是建议读者在最开始练习时还是加上变量类型的声明,便于加深映像,同时在多人协作中,显示声明变量类型会使代码更具有可读性(见仁见智)。

let hasNotFinished = true

数字类型(Number)

和JavaScript一样,TypeScript里的所有数字都是浮点数。 这些浮点数的类型是 number。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;

上面的例子中都是在定义变量的时候赋予了初始值,但是对于先定义后赋值的做法,建议先给变量定义数据类型。

字符串类型(String)

和JavaScript一样,可以使用双引号( ")或单引号(')表示字符串。但同时TypeScript支持ES6的模板字符串

let name: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ name }.

I'll be ${ age + 1 } years old next month.`;

数组类型(Array)

TypeScript有两种定义数组的方式:

let myList: number[] = [1,2,3]
let yourList: Array<number> = [1,2,3]

值得注意的是,在Javascript中,并不会限定数组中元素的类型,但是在TypeScript中一旦选定数组元素的类型,就不能再给该数组的元素赋予其他类型的值。

// javascript
let myList = [1, '2', [3], 4]
// typescript
let myList: number[] = [1,2,3,4]
myList[1] = '2' // error, 不能改变数组元素的类型 

下面我再举几个例子,方便扩展大家的理解:

let list: number[][]
list = [ [1,3,4], [2,3,4] ]
list = [ [1, '2'] ] // error
list = [ 1,2 ] // error  

上面的例子中,list为一个数组,它的子元素为一个数字类型的数组,所以它的子元素必须是数组类型,而且必须是数字类型的数组。 根据这个例子,大家可以举一反三,多多尝试,就能很好的理解TypeScript的数组类型了。

元组类型(Tuple)

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string和number类型的元组。 根据上面的描述,可以提取出几个关键点:

1. 元组是一个数组,可以通过数组的方式去访问数组元素,通过数组的方式操作元组;
2. 元组中元素的数量是固定的,每个元素的类型也是确定的,所以不能再去修改元素的类型,默认不允许向元组中添加新的元素

来看下面的例子:

let list: [number, string] = [1, '2']
console.log(list.length) // 2
list[2] = '3' // error

由于元组的类型和长度是固定的,所以使用场景并不丰富,需要在特定的场景中使用。

枚举类型(Enum)

枚举类型是JavaScript不具有的数据类型,但是在其他编程语言中是很常见的一种数据类型。使用枚举类型可以为一组数值赋予友好的名称。 下面举例说明枚举类型的用法:

enum Color { Red, Green, Blue }
let c: Color = Color.green
console.log(Color.Red) // 0
console.log(Color.Green) // 1
console.log(Color.Blue) // 2

枚举类型可以理解为一个由键值对组成的对象,它默认是从0开始赋值的,每一位递增1。 再来看下面的几个例子:

enum Color { Red = 2, Green, Blue }
console.log(Color.Red) // 2
console.log(Color.Green) // 3
console.log(Color.Blue) // 4
enum Color { Red, Green = 4, Blue }
console.log(Color.Red) // 0
console.log(Color.Green) // 4
console.log(Color.Blue) // 5

枚举类型初始值为字符串

enum Color1 { Red = '1', Green, Blue } // error: 需要给每个枚举元素赋予初值
enum Color2 { Red = '1', Green = 4, Blue }
console.log(Color2.Red) // '1'
console.log(Color2.Green) // 4
console.log(Color2.Blue) // 5

从上面的例子可以总结出下面几点:

1. 枚举在默认情况下是从0开始赋予初始值的,每一位递增1;
2. 枚举当前元素的值的上一位如果是number类型,那么下一位(在没有赋予初始值得情况下)默认赋值为上一位的值+1
3. 如果枚举中的上一位元素为字符串类型,那么当前的元素必须手动赋予初始值

Any类型

声明为any类型的变量,它的类型是不固定的,所以在赋予初始值后仍旧可以继续改变变量值的类型。当不给变量指定类型的时候,变量会默认被赋予any类型,直到给变量赋予初始值之后,TypeScript才会根据变量值推断出变量类型并确定该变量的数据类型。

let notSure: any = 5
notSure = '5'
notSure = [5]

let list: any[] = [1, '2', false]
list[1] = 2
list[2] = 'false'

Void类型

void类型与any类型,它表示没有任何类型。当函数没有返回值的时候,那么它的返回值类型会是void类型。

function warnUser(): void {
    console.log("This is my warning message");
}

声明一个void类型的变量没有什么大用,因为你只能为它赋予undefinednull

let unusable: void = undefined;

####Null 和 Undefined TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。 和 void相似,它们的本身的类型用处不是很大。当变量被定义为null(undefined)类型的时候,它们只能被赋值为null(undefined)。

// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
u = null // error
n = undefined // error

Never

never类型表示的是那些永不存在的值的类型。 下面是一些返回never类型的函数:

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}

Object类型

object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。 使用object类型,就可以更好的表示像Object.create这样的API。例如:

declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

类型断言

有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。

通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。

类型断言有两种形式。 其一是“尖括号”语法:

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;

另一个为as语法:

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在TypeScript里使用JSX时,只有 as语法断言是被允许的。

上述总结中,void、null、undefined、never、object、类型断言,我是截取了官方文档的内容,因为这些类型本身可能应用场景很少(void、null、undefined、never),或者不需要多讲(object),又或者官方说的更明晰(类型断言);除此以外,我参考了官方的说法,并更多地加入了自己的理解。

读完本文,我希望读者对于TypeScript至少能有以下几个认知:

  1. 定义变量时需要给变量指定类型;
  2. 类型写法是 :变量: 变量类型,类型后置;
  3. 类型一旦确定无法改变(不考虑any类型的说法);
  4. 对于类型断言有印象;

对于TypeScript类型系统,读者需要在实践中多多练习才能逐渐掌握,通过本文能有一个概念性的认识即可,一如古人言:纸上得来终觉浅,绝知此事要躬行