TypeScript(七)

101 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

😊 大家好,我是思淼MJ。

上篇文章总结了 TypeScript 的数组类型,今天继续来总结 TypeScript 的另一种类型。

函数类型

说到“函数类型”,就会想到JavaScript 中的“函数表达式”,那来结合JavaScript 中的函数表达式来对函数类型总结一下。

函数声明

在 JavaScript 中,有两种比较常见的定义函数的方式:函数声明和函数表达式。

先来举个简单的例子🌰:

// 函数声明
fonction getSum (x, y) {
    return x + y;
}


// 函数表达式
let getSum = fonction (x, y) {
    return x + y;
}

上面的例子如果使用 TypeScript ,需要对输入和输出进行约束,函数声明的类型定义为:

fonction getSum (x:number, y:number):number {
    return x + y;
}

🤔问题:在这种方式下,如果传递的参数多于或少于定义的参数,是被允许的吗?

📖答案:不允许。

比如上面的例子,我们调整为🌰:

fonction getSum (x:number, y:number):number {
    return x + y;
}
getSum(1,2,3);

执行上面的代码,会发现有以下报错:

//  error TS2346: Supplied parameters do not match any signature of call target.

当传递参数少于函数中定义的参数的时候,也会出现类似的报错信息。

所以,输入多于或少于函数中所要求的参数,是不被允许的。

函数表达式

如果首次将上面的函数表达式用 TypeScript 表达,可能会写成这样:

// 不知道有没有同学和我一样,写成这样😂
let getSum = fonction (x:number, y:number):number {
    return x + y;
}

上面的例子,其实只是对等号的右侧的匿名函数进行了约束,而左侧的 getSum 的类型只是通过类型推断推导出它的类型,真实的代码应该是这样的:

let getSum:(x:number, y:number) => number = fonction (x:number, y:number):number {
    return x + y;
}

🤔问题:那个 => 不是 ES6中的 箭头函数吗?

这里的 => 代表的含义并不同于 ES6 中的 箭头函数:

ES6 中,通常箭头的左侧代码是指 传递的参数,右侧是指,需要执行的功能逻辑;

而在 TypeScript 中,箭头的左侧代表输入的参数以及参数的类型,右侧则是指,输出结果的类型。

使用接口定义函数的形状

也可以通过使用接口来定义一个函数的形状,比如上面的例子🌰可以调整为:

interface sumType {
    (x:number, y:number): number;
}
let getSum:sumType = function (x:number, y:number) {
    return x + y;
}

通过上面的例子可以得出,使用接口定义函数的形状,简单来说就是对等号的左侧进行类型的限制约束。

可选参数

之前的文章中有提到过接口的“可选属性”,想必现在对“可选”的含义并不陌生。

前面有说到,输入多于或少于函数中要求的参数是不被允许的,那怎么才能定义参数为“可选参数”呢???

其实和接口的可选属性类似,使用 ? 表示可选的参数。

举个简单的例子🌰:

function getString (x:string, y?:string) {
    if (y) {
        return x + '+' + y;
    } else {
        return x
    }
}

getString('a'); // 'a'

getString('a', 'b'); // 'a+b'

比如如果对上面的例子进行调整为:

function getString (x?:string, y:string) {
    if (x) {
        return x + '+' + y;
    } else {
        return y
    }
}

getString(undefined, 'b');

执行了之后,会发现出现了以下报错:

// error TS1016: A required parameter cannot follow an optional parameter.

所以,需要注意的点是:可选参数必须写在必选参数的后面,也就是说可选参数的后面,不允许再出现必选参数。

参数默认值

ES6 中,可以给函数的参数添加默认值,在 TypeScript 中也是允许添加默认值的,会将添加的默认值的参数识别为可选参数。

举个简单的例子🌰:

function getString (x:string, y:string = '参数默认值') {
    return x + y;
}

getString('a'); // 'a参数默认值'

getString('a', 'b'); // 'ab'

不同的点是:可选参数必须在必选参数的后面,而参数默认值不受这些的约束,可以放在任意位置。

剩余参数

ES6 中,可以使用 ... 的方式来获取函数中的剩余参数。

比如下面的例子🌰:

fonction getArr (array, ...items) {
    items.map(item => {
        array.push(item);
    })
}

let a:any[] = [];

getArr(a, 1, 2, 3);

从上面的例子中,可以看出,items 是一个数组,所以可以使用数组类型来定义它,上面的例子即为:

fonction getArr (array:any[], ...items:any[]) {
    items.map(item => {
        array.push(item);
    })
}

let a = [];

getArr(a, 1, 2, 3);

同时从上面的例子可以得出,剩余参数为最后一个参数。

重载

重载就是允许一个函数不同数量或者类型参数时,作出不同的方式处理。

举个简单的例子🌰,实现一个反转参数的方法,比如我们输入 123 ,输出  321;输入 ‘hello’,输出 ‘olleh’。

fonction reverse (x:string | number):string | number {
    if (type of x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (type of x === 'string') {
        return x.toString().split('').reverse().join('');
    }
}

上面例子中的函数,有一个小小的缺点就是:

表达的不够精确,按理说应该输入的是字符串,输入的也应该是字符串;如果输入是数字,那输出就应该是数字。

这个时候,我们就可以使用 重载 来定义多个函数的类型。即:

fonction reverse(x:string):string;
fonction reverse(x:number):number;
fonction reverse (x:string | number):string | number {
    if (type of x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (type of x === 'string') {
        return x.toString().split('').reverse().join('');
    }
}

上面例子中的含义是:前两次都是对函数的定义,最后一次是对函数的实现。

同时在编辑器中,我们可以明确的看到对变量中类型的提示。

需要注意的点是:TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。