【TypeScript】TypeScript学习 — 函数和泛型

在这里插入图片描述

1、TypeScript中的函数

1.1 定义函数

函数是JavaScript应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义 行为的地方。
TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用。
对于JavaScript,定义一个函数可以使用function关键字或者函数表达式,例如:

function sum(a, b){
    return a + b;
}

此时函数的参数a,b类型是不确定的,如果你传入两个数字,那么会返回两数之和,如果传入的两个参数中包含了字符串或者两个都是字符串,那么就会返回拼接的字符串。

console.log(sum(1, 2));
console.log(sum(1, '2'));
console.log(sum('one', 'two'));

在这里插入图片描述
对于上述情况,我们可能会觉得函数功能变得更加强大了,不仅可以实现加法,还可以完成字符串的拼接,但是,这也存在一定的问题,很难从类型上找到预期的行为,即看到sum这个函数,一般只会想到两数相加,并不会想到字符串拼接。
在强类型语言中,例如c, Java中,定义一个函数,必须显式声明函数的返回值类型和每个参数的类型:

int sum(int a, int b){
	return a + b;
}

在JavaScript的基础上,TypeScript为函数和参数增加了类型的约束:

function sum(a: number, b: number): number {
    return a + b;
}

let sum = function(a: number, b: number): number { return a + b; };

当我们传入的a,b不是数值类型时,TypeScript便会报错。
我们可以给每个参数添加类型之后再为函数本身添加返回值类型。 TypeScript能够根据返回语句自动推断出返回值类型,因此我们通常省略它。因此,可以简化sum函数:

function sum(a: number, b: number) {
    return a + b;
}

1.2 可选参数和默认参数

TypeScript里的每个函数参数都是必须的, 也就是说,传递给一个函数的参数个数必须与函数期望的参数个数一致。

function buildName(firstName: string, lastName: string) {
    return firstName + " " + lastName;
}

let result1 = buildName("Bob");                  // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");         // ah, just right

JavaScript里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined。 在TypeScript里我们可以在参数名旁使用 ?实现可选参数的功能。 比如,我们想让last name是可选的:

function buildName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}

let result1 = buildName("Bob");  // Bob
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");  // Bob Adams

可选参数必须跟在必须参数后面。 如果上例我们想让first name是可选的,那么就必须调整它们的位置,把first name放在后面。

对于默认参数,也就是我们可以为函数的参数设置一个默认的值,如果给传入了值,那么就使用传入的值,否则使用默认值:

function buildName(firstName: string, lastName = "Smith") {
    return firstName + " " + lastName;
}

let result1 = buildName("Bob");                  // works correctly now, returns "Bob Smith"
let result2 = buildName("Bob", undefined);       // still works, also returns "Bob Smith"
let result3 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result4 = buildName("Bob", "Adams");         //  Bob Adams

与普通可选参数不同的是,带默认值的参数不需要放在必须参数的后面。 如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined值来获得默认值。 例如,我们重写最后一个例子,让 firstName是带默认值的参数:

function buildName(firstName = "Will", lastName: string) {
    return firstName + " " + lastName;
}

let result1 = buildName("Bob");                  // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");         // okay and returns "Bob Adams"
let result4 = buildName(undefined, "Adams");     // okay and returns "Will Adams"

1.3 剩余参数

必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在JavaScript里,你可以使用 arguments对象来访问所有传入的参数。

function sum(a, b){
    console.log(arguments)
    return a + b;
}
console.log(sum(1, 2));

在这里插入图片描述
或者使用展开运算符...

function sum(a, ...rest){
    console.log(rest)
    return a;
}

sum(1, 2, 3, 4);

在这里插入图片描述
TypeScript也使用了类似展开运算符来实现剩余参数:

function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

2、泛型

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。我们可以使用any完成上述功能:

function identity(arg: any): any {
    return arg;
}

但是,这也失去了TypeScript的意义,如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。

我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。

function identity<T>(arg: T): T {
    return arg;
}

我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。

我们把这个版本的identity函数叫做泛型,因为它可以适用于多个类型。 不同于使用 any,它不会丢失信息,像第一个例子那像保持准确性,传入数值类型并返回数值类型。

泛型函数的使用:

let output = identity<string>("myString");  // type of output will be 'string'

可以看到,使用了identity<string>的方法调用了泛型函数,但是,其实我们可以简化一下,因为编译器会根据传入的参数自动地帮助我们确定T的类型:

let output = identity("myString");  // type of output will be 'string'

泛型也可以使用数组、接口和类中。

泛型数组:

let a: Array<String> = [1,2,3];//不能将类型“number”分配给类型“String”。ts(2322)

let b: Array<Number> = [1, 2, 3];//all right

泛型接口:

interface IdentityInterface<T> {
    (arg: T): T;
}

泛型类:

class IdentityClass<T> {//定义一个泛型类
    initValue: T;
    add: (x: T, y: T) => T;
}

let res = new IdentityClass<number>();
res.initValue= 0;
res.add = function(x, y) { return x + y; };

总结:
如果事先不能知道类型,或者具体的类型在使用的时候才能确定,那就可以使用泛型。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小绵杨Yancy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值