函数类型(Function)
函数类型(Function)用来描述参数列表和返回值的类型。在TypeScript中,函数类型包含两部分:参数列表的类型和返回值的类型。
定义函数类型的语法格式为:(参数列表) => 返回值类型。
例如,下面的代码定义了一个函数类型,参数为两个number类型,返回值为number类型:
let myAdd: (x: number, y: number) => number;
使用定义的函数类型来声明一个函数:
let add: (x: number, y: number) => number;
add = function(x: number, y: number): number {
return x + y;
};
上面的代码中,使用let关键字声明了一个变量add,并使用函数类型来指定变量的类型。接着,将一个函数赋值给add变量,该函数接受两个number类型的参数,并返回一个number类型的结果。
可以看到,函数类型可以作为其他类型的一部分,比如作为变量的类型、作为函数的参数类型。这种灵活的函数类型的支持,使得在使用函数时能够更好地进行类型检查和类型推断。
可选参数和默认参数
在 TypeScript 中,可以使用可选参数和默认参数来增强函数的灵活性。
可选参数是指在定义函数时,某些参数可以传递也可以不传递。
在函数参数后面加上问号(?)可以将参数声明为可选参数。例如:
function greet(name: string, age?: number) {
console.log(`Hello, ${name}!`);
if (age) {
console.log(`You are ${age} years old.`);
}
}
greet("John");
greet("Jane", 25);
上面的代码中,函数greet
接受两个参数,其中age
参数被声明为可选参数。在函数体内,我们使用条件语句来判断是否传递了age
参数,并进行相应的处理。在调用greet
函数时,可以选择只传递name
参数或者同时传递name
和age
参数。
默认参数是指在定义函数时,可以为某些参数指定默认值。在函数参数后面使用等号(=)来为参数设置默认值。例如:
function greet(name: string, age: number = 18) {
console.log(`Hello, ${name}!`);
console.log(`You are ${age} years old.`);
}
greet("John");
greet("Jane", 25);
上面的代码中,函数greet
的age
参数被指定了默认值为18。在调用greet
函数时,如果不传递age
参数,那么将使用默认值18。如果传递了age
参数,那么将使用传递的值。
使用可选参数和默认参数可以灵活地处理函数调用时参数的传递情况,并且可以减少冗余的函数声明。
剩余参数
在 TypeScript 中,剩余参数(rest parameters)是一种用于表示接收任意数量的函数参数的语法。使用剩余参数,你可以在函数参数列表中使用三个点(…)加上一个参数名来表示剩余参数,它将接收函数调用时传递的所有额外参数,并将它们存储为一个数组。
下面是一个使用剩余参数的示例:
function sum(...numbers: number[]) {
let result = 0;
for (let num of numbers) {
result += num;
}
return result;
}
console.log(sum(1, 2, 3)); // 输出 6
console.log(sum(4, 5, 6, 7)); // 输出 22
在上面的示例中,sum
函数使用剩余参数 numbers
来接收任意数量的数字参数。函数体内,我们使用了 for...of
循环遍历 numbers
数组,并将所有参数累加到 result
变量中,最后返回结果。
通过使用剩余参数,你可以方便地处理任意数量的参数,而无需在函数声明中显式列出每个参数。
箭头函数
在 TypeScript 中,箭头函数(arrow functions)是一种更简洁的函数声明方式。箭头函数使用箭头(=>)来替代传统的 function
关键字,并遵循以下语法规则:
// 无参数的箭头函数
() => { ... }
// 一个参数的箭头函数
param => { ... }
// 多个参数的箭头函数
(param1, param2, ...) => { ... }
// 箭头函数的函数体只有一条表达式时可以省略花括号和 return 关键字
param => expression;
以下是一些使用箭头函数的示例:
// 无参数的箭头函数
const sayHello = () => {
console.log("Hello!");
};
sayHello(); // 输出:Hello!
// 一个参数的箭头函数
const double = num => {
return num * 2;
};
console.log(double(5)); // 输出:10
// 多个参数的箭头函数
const sum = (a, b) => {
return a + b;
};
console.log(sum(2, 3)); // 输出:5
// 多个参数的箭头函数体只有一条表达式时的简写形式
const multiply = (a, b) => a * b;
console.log(multiply(4, 5)); // 输出:20
使用箭头函数可以简化函数声明,并且它们的函数体更加简洁,特别是当函数体只有一条表达式时。它们还具有继承外部作用域的 this
值的特性,可以避免在使用回调函数时出现 this
绑定问题。
泛型函数和泛型接口
TypeScript 中的泛型函数和泛型接口是非常有用的特性,可以使函数和接口能够适用于不同类型的数据。
泛型函数允许我们在定义函数时使用类型参数。这样,我们就可以在函数体内使用这个类型参数来操作数据,而不用事先指定具体的类型。例如:
function reverse<T>(arr: T[]): T[] {
return arr.reverse();
}
const numbers = [1, 2, 3, 4, 5];
const result = reverse(numbers);
console.log(result); // [5, 4, 3, 2, 1]
上面的例子中,我们定义了一个泛型函数 reverse
,它接受一个类型为 T
的数组作为参数,并返回一个同样类型为 T
的反向数组。然后,我们调用了这个函数,并传入一个 number
类型的数组 numbers
,最后打印出了结果。
另外,我们还可以在函数定义时指定多个类型参数,使用逗号分隔。例如:
function mergeArrays<T, U>(arr1: T[], arr2: U[]): (T | U)[] {
return arr1.concat(arr2);
}
const numbers = [1, 2, 3];
const strings = ['hello', 'world'];
const result = mergeArrays(numbers, strings);
console.log(result); // [1, 2, 3, 'hello', 'world']
上面的例子中,我们定义了一个泛型函数 mergeArrays
,它接受一个类型为 T
的数组和一个类型为 U
的数组作为参数,并返回一个联合类型的数组。然后,我们调用了这个函数,并传入一个 number
类型的数组 numbers
和一个 string
类型的数组 strings
,最后打印出了结果。
泛型接口允许我们在定义接口时使用类型参数。这样,我们就可以在接口中使用这个类型参数来定义属性、方法等。例如:
interface MyArray<T> {
length: number;
push(item: T): void;
pop(): T | undefined;
}
class MyNumberArray implements MyArray<number> {
private items: number[] = [];
get length() {
return this.items.length;
}
push(item: number) {
this.items.push(item);
}
pop() {
return this.items.pop();
}
}
const numbers = new MyNumberArray();
numbers.push(1);
numbers.push(2);
numbers.push(3);
console.log(numbers.length); // 3
console.log(numbers.pop()); // 3
上面的例子中,我们定义了一个泛型接口 MyArray
,它有一个类型为 T
的属性 length
和两个方法 push
和 pop
。然后,我们实现了一个 MyNumberArray
类,它实现了 MyArray<number>
接口,表示这个类的实例是一个 number
类型的数组。最后,我们创建了一个 MyNumberArray
的实例 numbers
,以及使用了 push
和 pop
方法,并打印出了结果。
泛型类
在 TypeScript 中,我们也可以定义泛型类。
泛型类与泛型函数和泛型接口类似,可以在类的定义中使用类型参数,以便在类的成员中使用这个类型。使用泛型类可以使得类中的某些属性或方法适用于多种类型。
下面是一个使用泛型类的示例:
class GenericClass<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}
// 使用泛型类
const stringObj = new GenericClass<string>("Hello");
console.log(stringObj.getValue()); // 输出 "Hello"
const numberObj = new GenericClass<number>(100);
console.log(numberObj.getValue()); // 输出 100
在上面的示例中,我们定义了一个 GenericClass
泛型类,它具有一个类型参数 T
。在类的构造函数中,我们使用类型参数 T
声明了一个私有属性 value
,并在构造函数中初始化它。然后,我们在类中定义了一个 getValue
方法,该方法返回属性 value
的值。
通过在创建实例时指定不同的类型参数,我们可以使用 GenericClass
创建适用于不同类型的对象。在示例中,我们分别创建了一个 GenericClass<string>
类型的对象和一个 GenericClass<number>
类型的对象,并分别调用了它们的 getValue
方法来获取值。