我们之前介绍了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-numberas-string,这不是基本数据类型,而是我们自己写的一个字符串,这就叫做字面量类型,实际上,这里可以传任何类型的值,比如 addType: 1 | 'as-string',这个时候,这个参数只能接收数字1或者字符串'as-string'。这样看来,字面量类型和枚举有点像了。

通过type来定义类型

我们来看看上面这个add函数:

function add(val1: (number | string), val2: (number | string), addType: 'as-number' | 'as-string') { //... }

其中val1val2要求的类型是一样的,那么我们可以把它们写成一个吗?当然!!

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,这个类型的意思就是「数字」和「字符串」都可以,它包括了对numberstring的描述,所以它是一个「联合」。现在我们来看一下「交集类型」,交集类型&,从这个符号应该就可以看出来,它是「并且」的意思,好了,那么我们来看一下这个类型: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的所有「相交项」进行合并。(我觉得直接理解&符号会更直观一点~)