我们之前介绍了TS里的一些基本数据类型,要知道,在一个强类型的编程语言里,只靠基本数据类型是绝对不够的。所以,继续吧~
Union Types-联合类型
我们之前写过一个这样的例子:
let arr: any[];
arr = [1,'苹果','橘子'];
其实这里的any
,我们可以换成多个类型,也就是联合类型 ( number | string )
:
let arr: ( number | string )[];
arr = [1,'苹果','橘子'];
( number | string )
中间的竖线-|
就是或者的意思,也就是说这个数组的数组元素是number
或者string
都可以,所以里在列出的所有类型就是一个集合。
Literal type-字面量类型
还是拿之前的add
函数来举例:
function add(num1:number, num2:number) {
return num1 + num2;
}
现在这个函数,我想同时实现数字和字符串相加的功能,这个时候我就可以添加第三个参数作为标识,通过这个标识来判断是数字相加还是字符串相加:
function add(val1: (number | string), val2: (number | string), addType: 'as-number' | 'as-string') {
if ('as-number' === addType) {
return +val1 + +val2;
} else if ('as-string' === addType) {
return val1.toString() + val2.toString();
}
}
可以看到,参数addType
的类型限制是as-number
或as-string
,这不是基本数据类型,而是我们自己写的一个字符串,这就叫做字面量类型,实际上,这里可以传任何类型的值,比如 addType: 1 | 'as-string'
,这个时候,这个参数只能接收数字1
或者字符串'as-string'
。这样看来,字面量类型和枚举有点像了。
通过type来定义类型
我们来看看上面这个add
函数:
function add(val1: (number | string), val2: (number | string), addType: 'as-number' | 'as-string') { //... }
其中val1
和val2
要求的类型是一样的,那么我们可以把它们写成一个吗?当然!!
type AddValueType = number | string;
function add(val1: AddValueType, val2: AddValueType, addType: 'as-number' | 'as-string') { //... }
通过type
来定义类型,然后到任何地方都可以复用,同样的,addType
也可以进行定义:
type AddValueType = number | string;
type AddType = 'as-number' | 'as-string;
function add(val1: AddValueType, val2: AddValueType, addType: AddType) { //... }
函数相关类型
函数返回类型
假如我们有一个不返回任何值的函数,add
,麻烦你再出来一下吧~
function add(num1:number, num2:number) {
console.log(num1 + num2);
}
这个函数,我们没有return
任何数据,只是在里面打印了一下结果,这个时候我们可以给函数指定一个void
返回类型:
function add(num1:number, num2:number): void {
console.log(num1 + num2);
}
这样写,我们这个函数返回的是一个没有意义的值-undefined
。
但是我们大部分的函数是需要返回值的,例如add
,其实我们是需要return num1+num2
的,所以我们可以直接把void
换成我们想要的返回值类型即可,上面的例子应该返回number
。
function add(num1: number, num2: number): number {
return num1 + num2;
}
函数类型
函数也需要类型?没错,我们直接来看例子:
function add(num1: number, num2: number): number {
return num1 + num2;
}
function printMessage(msg: string): void {
console.log(msg);
};
两个很普通的函数,现在我们新建一个any
的变量,然后让它指向add
函数:
let fn;
fn = add;
fn(4,5);
嗯,这样可以执行,但是别忘了,fn还可以指向别的函数,报错在所难免~:
let fn;
fn = add;
fn = printMessage;
fn(4,5);
所以我们给函数添加类型是很有必要的,假如我们只想让fn的类型符合add
函数,那么可以直接添加函数类型:
let fn: (val1: number, val2: number) => number;
fn = add; //正确
fn = printMessage; //报错!!!
可以看到给函数添加类型的语法有点像箭头函数,但我们只需要在「箭头」后面加上返回类型就可以了,并不需要加花括号{ }
unknown
未知类型,假如用户输入一个字符,而用户界面又没有限制输入值的类型,那么这个值就可以被认为是unknown
类型:
let userInput: unknown;
//假如用户输入一个 5,这里我们直接对userInput进行赋值来模拟
userInput = 5;
//然后用户又输入一个字符串:
userInput = 'Daniel';
嗯?之前不是说过any
吗?感觉和any
没啥区别啊?其实还是有区别的,我现在再新建一个userName: string
,然后再将userInput的值赋给它:
let userInput: unknown;
let userName: string;
userInput = 5;
userInput = 'Daniel';
userName = userInput; //报错!!!
错误如下:
道理很简单,userName
已经明确了是string
类型,而userInput
不确定是什么类型,一会儿被赋值成数字,一会儿被赋值成字符串。但是如果把unknown
换成any
则不会报错:
//将userInput改成any 类型
let userInput: any;
let userName: string;
userInput = 5;
userInput = 'Daniel';
userName = userInput;
never
再来看一下之前说的没有返回值的函数:
function add(num1:number, num2:number): void {
console.log(num1 + num2);
}
这个函数虽然没有返回值,但是我们调用一下这个函数,还是会得到一个undefined
。那么如果一个函数连undefined
都没有的话,我们就可以把void
改成never
:
function gotError(message: string): never {
throw message;
}
gotError('Error 500');
gotError
这个函数连undefined
都不会返回,因为throw会直接把让程序挂掉,所以这里用never
再合适不过了。
交集类型
前面我们有说过「联合类型」,也就是中间用竖线|
隔开的这种形势:number | string
,这个类型的意思就是「数字」和「字符串」都可以,它包括了对number
和string
的描述,所以它是一个「联合」。现在我们来看一下「交集类型」,交集类型&
,从这个符号应该就可以看出来,它是「并且」的意思,好了,那么我们来看一下这个类型:number & string
,??? 这是啥?一个变量怎么可能即是number
又是string
呢?不科学!是的,这样写是不合法的,所以&
是用在对象类型定义上的:
type Person = {
name: string,
gender: string
}
type Student = {
name: string,
subjects: string[]
};
let student: Person & Student = {
name: 'Daniel',
gender: '男',
subjects: ['语文', '数学', '英语']
}
例子一贴出来,你可能就立马明白了,这不就是把对象所有key都合并在一起吗?是的,没错,但是你有没有一个疑问,为什么这个叫做「交集类型」呢?它看起来像是取「并集」的吧?其实这里的「交集」指的是把对象key的所有「相交项」进行合并。(我觉得直接理解&
符号会更直观一点~)