TS的一些基础知识很多前端小伙伴都略知一二,但作为一个连载文章,我还是希望能从基础到进阶,一步步来,系统的介绍一下typeScript,这篇聊聊基础的的数据类型:
TypeScript
数据类型
- Boolean类型
- Nubmer类型
- String类型
- Array类型
- Tuple类型
- Object类型
- Enum类型
- Symbol类型
- Any类型
- Unknown类型
- Void类型
- Null类型
- Undefined类型
- 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}]
定义对象数组时如果定义了name
和age
,那对象中只能包含字符串的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.数字枚举
例一.
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
此时Red
是3
,但Orange
也是3
,当访问JuejinEnum
的3
时,输出Orange
,有点类似对象的重载。
四个例子看的云里雾里,为什JuejinEnum
访问3
时Orange
,而访问Red
,Orange
输出都为3
。这里就要看看他编译成JS
到底是什么样:
感觉好乱,一点点研究,首先定义了一个
undefined
的JuejinEnum
,下面是一个自执行函数,将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 Orange
和 Key Red
未发生重载,值都为3
。
2.字符串
enum JuejinEnum {
Red = 'Red', // Red
Green = 'Green', // Green
Yellow = 'Yellow', // Yellow
}
字符串枚举,每个成员必须是字符串的字面量,字符串可以重复,但不会生成反向映射,以下是编译后的结果:
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"]
);
编译出来是这样:
枚举属性在编译阶段被删除,他可以使得编译后的代码更简洁,并与Javascript的状态保持一致。
3.外部枚举
外部枚举需要用declare
声明语句,使用时要谨慎,该枚举不会生成反向映射
declare enum JuejinEnum {
Red = 0,
Green,
Yellow,
Blue,
}
console.log(JuejinEnum)
编译出来后只有一个打印JuejinEnum
的语句。编译后并没有该枚举值,这就很奇怪,声明的外部枚举既然什么都没有,更不能访问,要他有何用?
官网是这样描述的:外部枚举用来描述已经存在的枚举性的形状。
可以这样理解:他是来描述当前上下文已存在对象的样子。在编译后不增加代码量的情况下,可以让开发者了解其他文件中同一作用域下的变量,并可以在TS中引用和访问。但他的初始化和类型表达规则必须符合枚举规则,所以能描述的样子也仅限于适合枚举形式的对象。\
打印值
4
3
我们发现外部枚举是无法重新给对象赋值的
4.外部常量枚举
但对于外部常量枚举值,是可以进行重新定义,而不引用other.js
中的变量。
也是官方所描述的:外部枚举值与非外部枚举值之间有一个重要的区别,在正常的枚举里,没有初始化方法的成员被当成常数成员。对于非常数的外部枚举而言,没有初始化方法时被当做需要经过计算的。
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){}
}
\
如果此文章对您有帮助或启发,那便是我的荣幸