TypeScript第二章:TS基础--数据类型

214 阅读9分钟

TS的一些基础知识很多前端小伙伴都略知一二,但作为一个连载文章,我还是希望能从基础到进阶,一步步来,系统的介绍一下typeScript,这篇聊聊基础的的数据类型:

TypeScript数据类型

  1. Boolean类型
  2. Nubmer类型
  3. String类型
  4. Array类型
  5. Tuple类型
  6. Object类型
  7. Enum类型
  8. Symbol类型
  9. Any类型
  10. Unknown类型
  11. Void类型
  12. Null类型
  13. Undefined类型
  14. Never类型 TS作为强类型语言,在定义变量前需要先声明他的类型,当然如果不声明,TS会默认使用第一次使用的数据类型,以后以此类型进行类型约束,但不推荐此写法,因为会引起未知的错误,语义化不强。TS更加细分了变量类型 不像JS把变量分为原始类型和引用类型。

1. Boolean类型

 // 布尔类型,与js一致,在想声明布尔类型时使用boolean
 let showPop: boolean = false;
 showPop = !0

后面有隐式类型转换 !0 结果为 true 也可以

2. Nubmer类型

 // 数字类型,与js一致,在想声明数字类型时使用number
let age: number = 1;
age = NaN;
age = Infinity;
age = +Infinity;
age = -Infinity;
age = 1;
age = 13.1415926;

number类型时,变量可以接受包括NaN ±Infinity 以及浮点数

3.String类型

 // 字符串类型,与js一致,在想声明字符串类型时使用string
let intor: string = '技术直男星辰';
intor = ‘今年28岁’;

4. Array类型

 // 数组类型,与js一致,在想声明数组类型时有两种方式
let oneTypeArr: number[] = [1,2,3]; // 类型+方括号方法定义
let twoTypeArr: Array<number> = [1,2,3]; //数组的泛型定义
// 当数字中有多个类型时使用联合类型 用 | 分割:
let arr1:(number | string)[] = [1, '技术直男星辰', 3]
let arr2: Array<number | string> = [1, '技术直男星辰', 3]
// 定义对象数组时
let userInfo1: Array<{name:string,age:number}> = [{name:'技术直男星辰',age:28}]
let userInfo2: {name:string,age:number}[] = [{name:'技术直男星辰',age:28}]

定义对象数组时如果定义了nameage,那对象中只能包含字符串的name和数字类型的age,当然也有可选择配制或者可以添加任何数据类型,放在后面聊。

5. Tuple类型

元组类型在JS中是不存在的,其实概念很简单,规定好一定长度的数组,并定义好每一个元素的数据类型。

 // 元组类型
 let tup: [string,number,string] = ['技术直男星辰',28,'男']
 tup.push('1');
 tup.push(true) // 报错

首先string,number,string限制了数组只能有三个元素,并且每个元素的数据类型必须一一对应每一个声明的数据类型。但细心的小伙伴发现元组的形式跟数组一样,那我们做个push操作,感觉也没问题,但当push一个布尔类型时,报错了。得出结论就是:越界的元素必须跟元组定义的数据类型一致

6.Object类型

表示非原始类型,除number,string,boolean,symbol,null,undefined之外的类型,主要可以让TS知道,这个类型可以调用Object方法。在开发当中,对对象的定义更多用的是类型别名与接口

let obj:object = {name:'技术直男星辰'}

7.Enum类型

枚举类型是TS中特有的,他可以清晰的表达意图或创建一组有区别的用例,用于取值在一定范围的场景,一周有七天,颜色限定为红绿蓝等。他支持数字字符串的枚举。
对与TS的枚举,编译成JS时,一般情况下是成反向映射关系。往后看,有二般情况,也会解释什么是反向映射。
枚举我们可以从两个维度去理解

  1. 按照枚举成员分类(数字、字符串、异构)
  2. 声明方式分类(普通枚举,常量枚举,外部枚举,外部常量枚举)
按照枚举成员分类

1.数字枚举
例一.

enum JuejinEnum {
    Red, // 0
    Green, // 1
    Yellow // 2
}

当不对枚举成员定义或未初始化时TS会初始化第一项为 0 后续每项 +1
例二

enum JuejinEnum {
    Red = 1, // 1
    Green, // 2
    Yellow // 3
}

有初始化动作时,在初始化基础上,后续每项 +1
例三

enum JuejinEnum {
    Red, // 0
    Green = 5, // 5
    Yellow, // 6
    Orange = -1, // -1
    Blue, // 0
} 

第一个成员未初始化为0,后面的在初始化基础上,后续每项 +1,负数也同理。
例四

enum JuejinEnum {
    Red = 3, // 3
    Green = 1, // 1
    Yellow, // 2
    Orange, // 3
    Blue, // 4
}
console.log(JuejinEnum[3]) // Orange
console.log(JuejinEnum[Orange]) // 3
console.log(JuejinEnum[Red]) // 3

此时Red3,但Orange也是3,当访问JuejinEnum3时,输出Orange,有点类似对象的重载。
四个例子看的云里雾里,为什JuejinEnum访问3Orange,而访问RedOrange 输出都为3。这里就要看看他编译成JS到底是什么样:

image.png 感觉好乱,一点点研究,首先定义了一个undefinedJuejinEnum,下面是一个自执行函数,将JuejinEnum传入到了函数体中并进行对他的一系列加工:

JuejinEnum[JuejinEnum["Red"] = 3] = "Red";

JuejinEnum["Red"] = 3 执行之后 JuejinEnum 创建了一个名称为Red的对象成员,同时执行后打印的结果为所赋值3,所以这一句话执行了两个操作

JuejinEnum[3] = "Red";
JuejinEnum["Red"] = 3;

以下每一个都是这种执行方式,这就是反向映射3=>Red Red=>3 1=>Green Green=>1 2=>Yellow Yellow=>2 3=>Orange Orange=>3 4=>Blue Blue=>4,其中3是发生了对象重载,所以 Key 3对应了后面的Orang,而Key OrangeKey Red 未发生重载,值都为3
2.字符串

enum JuejinEnum {
    Red = 'Red', // Red
    Green = 'Green', // Green
    Yellow = 'Yellow', // Yellow
}

字符串枚举,每个成员必须是字符串的字面量,字符串可以重复,但不会生成反向映射,以下是编译后的结果:

image.png 3.异构枚举

enum JuejinEnum {
    Red = 0, // 0
    Green = 'Green', // Green
    Yellow = 'Yellow', // Yellow
}

不推荐如此使用,如果使用时请注意:当第一个枚举成员初始化为字符串时,后面所有的成员都必须初始化成字符串。内部运行机制是不初始化,自动在上一个值进行 ++ 运算。而字符串 ++NaN

声明方式分类

1.普通枚举
普通枚举就是如上所说的枚举样子。它还可以有计算能力,但length只能在普通枚举上使用,而且不带初始化器的枚举,包括'Green'.length,后面如果再有枚举成员,必须有一个number类型的初始化值,否则编译出错。因为'Green'.length属于计算值。

enum JuejinEnum {
    Red = 0, // 0
    Green = 'Green'.length, // 5
}

2.常量枚举 常量枚举也可以有计算属性,但是含字符串成员的枚举不允许使用计算值。编译出来的JS与普通枚举也有不同:

const enum JuejinEnum {
  Red = 0, // 0
  Green = 1 % 2, // 1
  Yellow = +1, // 1
  Blue = 1 << 1, //2
}
console.log(
  JuejinEnum["Red"],
  JuejinEnum["Yellow"],
  JuejinEnum["Green"],
  JuejinEnum["Blue"]
);

编译出来是这样:

image.png 枚举属性在编译阶段被删除,他可以使得编译后的代码更简洁,并与Javascript的状态保持一致。
3.外部枚举
外部枚举需要用declare声明语句,使用时要谨慎,该枚举不会生成反向映射

declare enum JuejinEnum {
  Red = 0, 
  Green, 
  Yellow,
  Blue,
}
console.log(JuejinEnum)

编译出来后只有一个打印JuejinEnum的语句。编译后并没有该枚举值,这就很奇怪,声明的外部枚举既然什么都没有,更不能访问,要他有何用?
官网是这样描述的:外部枚举用来描述已经存在的枚举性的形状。
可以这样理解:他是来描述当前上下文已存在对象的样子。在编译后不增加代码量的情况下,可以让开发者了解其他文件中同一作用域下的变量,并可以在TS中引用和访问。但他的初始化和类型表达规则必须符合枚举规则,所以能描述的样子也仅限于适合枚举形式的对象。\

image.png 打印值 4 3
我们发现外部枚举是无法重新给对象赋值的

4.外部常量枚举
但对于外部常量枚举值,是可以进行重新定义,而不引用other.js中的变量。

image.png 也是官方所描述的:外部枚举值与非外部枚举值之间有一个重要的区别,在正常的枚举里,没有初始化方法的成员被当成常数成员。对于非常数的外部枚举而言,没有初始化方法时被当做需要经过计算的。

8. Symbol类型

在我的调研中,TS没有对Symbol进行语法拓展,与JS是一致的。有大牛知道什么异同也可在评论区补充。

9. Any类型

在使用any时,TS不做任何类型检测,同时也没有任何类型方法的提示,any是顶级类型,任何值都可以赋到用any定义的变量。

let name;
name = '技术直男星辰'

当刚定义name时,它的类型没有定义,此时类型是any,后续定义了一个字符串,以后name变量为字符串类型。 另外比如来自用户输入或第三方代码库,不想对这些值进行类型检查,可以用any定义。但为了代码的健壮性,尽量少的使用any
紧接着介绍unknown,再看看他们的区别。

10. Unknown类型

unkonwn相对any来说,对类型要求更加严格,但算是顶级类型。unknown因为是未知类型,不允许访问属性,不允许赋值给其他有明确类型的值

let unknownName: unknown = '技术直男星辰';
let anyName: any = '技术直男星辰'

const name1: string = unknownName // Error
const name2: string = anyName // OK

unknownName.msg // Error

const unknownObj: unknown = { msg:'TS基础' }
const anyObj: unknown = { msg:'TS基础' }
unknownObj.msg // Error
anyObj.msg // TS基础

unknownName = anyName // OK
anyName = unknownName // OK

12. Void类型

void 类型表示没有任何类型,他可以定义一个没有返回值的函数,或值为null undefined的变量。

function sayName(){
    console.log('技术直男星辰')
}
const name: void = undefined
const name1: void = null

13. Null类型 14. Undefined类型

null undefined 是任何类型的子类型,也就是说任何类型的数据都可以被定义为null undefined。这两个类型也可以相互赋值。

let name: string = '技术直男星辰';
name = null // OK
name = undefined // OK

let unde: undefined = undefined
const nul:null = null
unde = nul // OK

15. Never类型

never表示永远不存在的值的类型。例如函数最终的返回值是一个Error,或者有无法达到的终点,无限循环。
never是一个变量时,其实是没有意义的,即时any也无法复制给nerver

function error(msg: string): never {
    throw new Error(msg)
}

function infiniteLoop(): never {
    while (true){}
}

\


如果此文章对您有帮助或启发,那便是我的荣幸