typescript基础篇(2):数据类型

时间:2022-07-22
本文章向大家介绍typescript基础篇(2):数据类型,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

2. 数据类型

Ts在es 6基础上加了不少类型。同时还弄出了不少玩法。本章从基础数据类型开始讲起

注意:在ts中,定义数据类型,除了Function,其它全部都是开头小写。

2.1 基本类型

在helloworld案例中,就已经使用了类型注解,相当于强类型语言中类型声明:

let greeting = (person: string) => `Hello, ${person}` // 参数person必须为字符串

基本的语法是:

(变量/函数):type

2.1.1 简单基础类型

对于最基础的数据类型:

// 原始类型
let bool: boolean = true
let bool2:boolean = 'true' // 报错
let num: number = 123
let str: string = "123" // 等价于 let str = '';

如果你不按照规矩进行赋值,就要报错。

2.1.2 数组

如果你要定义一个数组,你可以这么操作:

// 完全由数字组成的数组,二者等价
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]
// 由数字 或 字符串组成的数组
let arr3: Array<number | string> = [1, "2", 3]

2.1.3 元组

元组可以理解为是一种规定了数组长度和对应元素类型的特殊数组,它的定义也类似:

// 元组类型:限定了数组成员的类型和个数
let tuple:[number,string]= [1,'2']
let tuple: [number, string] = ["1", "2"] // 报错:Type 'string' is not assignable to type 'number'.
let tuple: [number, string] = [1, "2",3] // 报错:Types of property 'length' are incompatible.Type '3' is not assignable to type '2'.

但是,如果你对元组进行push,就不报错了。(实际开发强烈不建议这么骚操作)

let tuple: [number, string] = [1, "2"]
tuple.push(3) // 不报错
console.log(tuple) //[1,'2',3]
tuple[2] // 越界访问报错!

2.1.4 函数

我们用es6的习惯写一个加法函数:

const add = (x, y) => x + y

这种实践是不好的,因为x,y都有可能是任何数据类型(any)。直接相加是要出问题的。所以解决方案是:

const add = (x: number, y: number) => x + y // 限定入参必须为数字
const add2 = (x: number, y: number): number => x + y // 限定返回值也必须为数字s

2.1.5 对象

假如我们在ts中这么定义了一个对象:

const obj: object = {
  x: 1,
  y: 2,
}
obj.x = 3 // 警告:obj上未定义属性'x'

所以,你应该写明白obj上x和y的属性:

const obj: { x: number; y: number } = { x: 1, y: 2 }
obj.x = 3

2.1.6 symbol

symbol的含义就是:具有唯一的值:

const s1: symbol = Symbol()
const s2 = Symbol()
console.log(s1 === s2) // false

2.1.7 其它数据类型

在ts的定义中,undefined和null是任何其它数据类型的子类型,按理来说类似这种操作是应该允许的:

let aaa: number = 1
aaa = undefined

结果报错了。这时就应该去配置项tsconfig中设置strictNullChecks:false

let aaa: number|undefined = 1
aaa = undefined

在js中你可以声明undefined这个变量。

// 浏览器环境下
(function(){
    const undefined = 0;
    console.log(undefined);
})()

// 0

那么在这个闭包中,undefined就是0。

js中void是一种操作符,在ts中,返回真正的undefined

还有一个很出名的就是any类型,表示被赋值什么类型都可以。(实现了js的功能。不建议)

never类型:一下两种情况,返回never,表示永远不会有返回值:

const err = () => {
  throw new Error("err")
}
const endless = () => {
  while (true) {}
}

2.2 枚举类型(enum)

假设有一个用户登录系统,根据角色来显示不同的界面。我们用传统js的思维写一段判断角色的逻辑:

const initByRole = role => {
  if (role === 1 || role === 2) {
    // do sth
  } else if (role == 3 || role == 4) {
    // do sth
  } else if (role == 5) {
    // do sth
  } else {
    // do sth
  }
}

这段代码问题明显:

1.可读性极差:没有文档基本没人敢改。2.硬编码问题:如果要改,改动肯定很大。

如果到了ts,可以用枚举类型来处理这种场景。

所谓枚举类型者,就是一组有名字的常量组合。比方说手机通讯录:

•张三->10086•李四->10010

我打电话给张三时,直接从通讯录检索器名字即可,很少一个个按键拨电话。当然你想通过电话来找人,也是可以的。

2.2.1 数字枚举

在ts中,可以使用数字枚举来定义5个角色的映射

// 数字枚举
enum Role {
  Reporter, // 0
  Developer, // 1
  Maintainer, // 2
  Owner, // 3
  Guest, // 4
}

// Role.Reporter -> 0
// Role[0] -> Reporter

有了枚举类型,你可以通过属性来索引,也可以通过值来索引。

如果你尝试打印,发现这些其实都是普通的的Object对象:

它的编译过程是:

var Role;
(function (Role) {
    Role[Role["Reporter"] = 0] = "Reporter";
    Role[Role["Developer"] = 1] = "Developer";
    Role[Role["Maintainer"] = 2] = "Maintainer";
    Role[Role["Owner"] = 3] = "Owner";
    Role[Role["Guest"] = 4] = "Guest";
})(Role || (Role = {}));

就是反向映射。

2.2.2 字符串枚举

对于枚举类型,完全可以人工定义:

enum Msg {
  success = "成功",
  Fail = "失败",
}

再看看编译结果:

var Msg;
(function (Msg) {
    Msg["success"] = "u6210u529F";
    Msg["Fail"] = "u5931u8D25";
})(Msg || (Msg = {}));

显然无法做到根据"成功"索引success——也就是说,对于字符串枚举,是没法做到反向映射的。

2.2.3 异构枚举

当然你可以字符串和数字放在一个枚举对象,称之为异构枚举。

enum Aaa {
  a = 1,
  b = "1",
}

编译结果

(function (Aaa) {
    Aaa[Aaa["a"] = 1] = "a";
    Aaa["b"] = "1";
})(Aaa || (Aaa = {}));

很明显这种操作很容易混淆,也是不建议使用的。

2.2.4 枚举类型的性质

•枚举成员的值,是不能修改的。(只读)•对于枚举类型,定义值有几种情况:•没有定义值。•对其它枚举属性的引用。•常量表达式:编译时被计算出来。•非常量表达式:如arr.length:编译时被保留•常量枚举:比如

const enum Month{
    Jan=1,
  Feb=2,
  Mar=3
}

是不会被编译的。那又有什么意义呢?

可以引用常量枚举的表达式,虽然编译不存在这个Month对象,但通过常量枚举,减少了代码的复杂度。

const enum Month {
  Jan = 1,
  Feb = 2,
  Mar = 3,
}
let month = [Month.Jan, Month.Feb, Month.Mar]
console.log(month)

编译结果为:

var month = [1 /* Jan */, 2 /* Feb */, 3 /* Mar */];
console.log(month);

•枚举类型和枚举成员都可以作为类型来定义。枚举类型不同的枚举值,不可项目比较。