Appearance
TypeScript 函数
函数是 TypeScript 中重要的代码组织和复用方式。TypeScript 提供了丰富的函数特性,包括类型注解、函数重载、箭头函数、可选参数、默认参数、剩余参数等。本文将详细介绍 TypeScript 中的函数。
1. 函数定义
函数声明
typescript
function add(a: number, b: number): number {
return a + b;
}
console.log(add(1, 2)); // 输出:3函数表达式
typescript
const add = function(a: number, b: number): number {
return a + b;
};
console.log(add(1, 2)); // 输出:3箭头函数
typescript
const add = (a: number, b: number): number => {
return a + b;
};
// 简化版(当函数体只有一条返回语句时)
const add = (a: number, b: number): number => a + b;
console.log(add(1, 2)); // 输出:32. 参数类型
TypeScript 允许为函数参数指定类型,这样可以在编译时检查参数类型是否正确。
typescript
function greet(name: string, age: number): string {
return `Hello, ${name}! You are ${age} years old.`;
}
console.log(greet("John", 30)); // 输出:Hello, John! You are 30 years old.
// console.log(greet("John", "30")); // 错误:类型 'string' 不能赋值给类型 'number'3. 返回类型
TypeScript 允许为函数指定返回类型,这样可以在编译时检查函数返回值的类型是否正确。
typescript
function add(a: number, b: number): number {
return a + b;
}
function greet(name: string): string {
return `Hello, ${name}!`;
}
function log(message: string): void {
console.log(message);
}
function throwError(message: string): never {
throw new Error(message);
}4. 可选参数
TypeScript 允许函数参数是可选的,使用 ? 标记。
typescript
function greet(name: string, age?: number): string {
if (age) {
return `Hello, ${name}! You are ${age} years old.`;
} else {
return `Hello, ${name}!`;
}
}
console.log(greet("John")); // 输出:Hello, John!
console.log(greet("John", 30)); // 输出:Hello, John! You are 30 years old.5. 默认参数
TypeScript 允许为函数参数设置默认值。
typescript
function greet(name: string, age: number = 18): string {
return `Hello, ${name}! You are ${age} years old.`;
}
console.log(greet("John")); // 输出:Hello, John! You are 18 years old.
console.log(greet("John", 30)); // 输出:Hello, John! You are 30 years old.6. 剩余参数
TypeScript 允许函数接收任意数量的参数,使用 ... 标记。
typescript
function sum(...numbers: number[]): number {
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 输出:15
console.log(sum(1, 2)); // 输出:37. 函数重载
TypeScript 允许为同一个函数定义多个签名,这称为函数重载。
typescript
// 函数重载签名
function reverse(str: string): string;
function reverse(arr: number[]): number[];
// 函数实现
function reverse(input: string | number[]): string | number[] {
if (typeof input === "string") {
return input.split("").reverse().join("");
} else {
return input.slice().reverse();
}
}
console.log(reverse("hello")); // 输出:olleh
console.log(reverse([1, 2, 3, 4, 5])); // 输出:[5, 4, 3, 2, 1]8. 箭头函数
箭头函数是一种更简洁的函数写法,它没有自己的 this、arguments、super 或 new.target。
基本语法
typescript
// 无参数
const greet = (): string => "Hello!";
// 单个参数
const greet = (name: string): string => `Hello, ${name}!`;
// 多个参数
const add = (a: number, b: number): number => a + b;
// 函数体多行
const add = (a: number, b: number): number => {
const result = a + b;
return result;
};箭头函数与 this
箭头函数没有自己的 this,它会捕获定义时的 this 值。
typescript
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 使用普通函数
greet1() {
setTimeout(function() {
console.log(`Hello, my name is ${this.name}.`); // 错误:this 指向 setTimeout 的调用者
}, 1000);
}
// 使用箭头函数
greet2() {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}.`); // 正确:this 指向 Person 实例
}, 1000);
}
}
const person = new Person("John", 30);
person.greet1(); // 输出:Hello, my name is undefined.
person.greet2(); // 输出:Hello, my name is John.9. 函数类型
TypeScript 允许定义函数类型,用于描述函数的参数类型和返回类型。
函数类型定义
typescript
type AddFunction = (a: number, b: number) => number;
const add: AddFunction = (a, b) => a + b;
console.log(add(1, 2)); // 输出:3函数类型作为参数
typescript
type AddFunction = (a: number, b: number) => number;
function calculate(a: number, b: number, operation: AddFunction): number {
return operation(a, b);
}
const add: AddFunction = (a, b) => a + b;
const subtract: AddFunction = (a, b) => a - b;
console.log(calculate(10, 5, add)); // 输出:15
console.log(calculate(10, 5, subtract)); // 输出:5函数类型作为返回值
typescript
type AddFunction = (a: number, b: number) => number;
function createAddFunction(): AddFunction {
return (a, b) => a + b;
}
const add = createAddFunction();
console.log(add(1, 2)); // 输出:310. 泛型函数
TypeScript 允许定义泛型函数,用于处理不同类型的参数。
typescript
function identity<T>(value: T): T {
return value;
}
console.log(identity(1)); // 输出:1
console.log(identity("hello")); // 输出:hello
console.log(identity(true)); // 输出:true
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
console.log(pair(1, "hello")); // 输出:[1, "hello"]
console.log(pair("hello", true)); // 输出:["hello", true]11. 递归函数
递归函数是指在函数体内调用自身的函数。
typescript
function factorial(n: number): number {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
console.log(factorial(5)); // 输出:120
function fibonacci(n: number): number {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(10)); // 输出:5512. 异步函数
TypeScript 支持异步函数,使用 async 和 await 关键字。
typescript
async function fetchData(): Promise<string> {
// 模拟网络请求
return new Promise((resolve) => {
setTimeout(() => {
resolve("Data fetched successfully!");
}, 1000);
});
}
async function processData() {
console.log("Start fetching data...");
const data = await fetchData();
console.log(data);
console.log("Data processed successfully!");
}
processData();
// 输出:
// Start fetching data...
// Data fetched successfully!
// Data processed successfully!13. 函数的最佳实践
1. 使用类型注解
为函数参数和返回值添加类型注解,提高代码的可读性和类型安全性。
typescript
// 推荐
function add(a: number, b: number): number {
return a + b;
}
// 不推荐
function add(a, b) {
return a + b;
}2. 优先使用箭头函数
对于简短的函数,优先使用箭头函数,使代码更简洁。
typescript
// 推荐
const add = (a: number, b: number): number => a + b;
// 不推荐
function add(a: number, b: number): number {
return a + b;
}3. 使用默认参数替代可选参数
当参数有合理的默认值时,使用默认参数替代可选参数。
typescript
// 推荐
function greet(name: string, age: number = 18): string {
return `Hello, ${name}! You are ${age} years old.`;
}
// 不推荐
function greet(name: string, age?: number): string {
const actualAge = age || 18;
return `Hello, ${name}! You are ${actualAge} years old.`;
}4. 使用剩余参数处理可变数量的参数
当函数需要处理可变数量的参数时,使用剩余参数。
typescript
// 推荐
function sum(...numbers: number[]): number {
return numbers.reduce((acc, num) => acc + num, 0);
}
// 不推荐
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}5. 使用函数重载处理不同类型的参数
当函数需要处理不同类型的参数时,使用函数重载。
typescript
// 推荐
function reverse(str: string): string;
function reverse(arr: number[]): number[];
function reverse(input: string | number[]): string | number[] {
if (typeof input === "string") {
return input.split("").reverse().join("");
} else {
return input.slice().reverse();
}
}
// 不推荐
function reverse(input: any): any {
if (typeof input === "string") {
return input.split("").reverse().join("");
} else if (Array.isArray(input)) {
return input.slice().reverse();
}
}6. 避免使用 any 类型
尽量避免使用 any 类型,使用更具体的类型或泛型。
typescript
// 推荐
function identity<T>(value: T): T {
return value;
}
// 不推荐
function identity(value: any): any {
return value;
}14. 常见错误
1. 忘记添加类型注解
忘记为函数参数和返回值添加类型注解,导致类型检查失效。
typescript
// 错误
function add(a, b) {
return a + b;
}
// 正确
function add(a: number, b: number): number {
return a + b;
}2. 箭头函数的 this 绑定
在使用箭头函数时,没有注意到它会捕获定义时的 this 值。
typescript
// 错误
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
greet() {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}.`);
}, 1000);
}
}
// 正确(与上面相同,因为箭头函数会捕获定义时的 this)
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
greet() {
setTimeout(() => {
console.log(`Hello, my name is ${this.name}.`);
}, 1000);
}
}3. 函数重载的顺序
函数重载的顺序很重要,应该将更具体的重载签名放在前面。
typescript
// 错误
function reverse(arr: number[]): number[];
function reverse(str: string): string;
function reverse(input: string | number[]): string | number[] {
// 实现
}
// 正确
function reverse(str: string): string;
function reverse(arr: number[]): number[];
function reverse(input: string | number[]): string | number[] {
// 实现
}4. 递归函数的类型注解
递归函数需要显式添加返回类型注解,否则 TypeScript 可能无法推断类型。
typescript
// 错误
function factorial(n: number) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
// 正确
function factorial(n: number): number {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}总结
TypeScript 提供了丰富的函数特性,包括:
- 函数定义:函数声明、函数表达式、箭头函数
- 参数类型:为函数参数指定类型
- 返回类型:为函数指定返回类型
- 可选参数:使用
?标记可选参数 - 默认参数:为参数设置默认值
- 剩余参数:使用
...处理可变数量的参数 - 函数重载:为同一个函数定义多个签名
- 箭头函数:更简洁的函数写法,没有自己的
this - 函数类型:定义函数的类型
- 泛型函数:处理不同类型的参数
- 递归函数:在函数体内调用自身
- 异步函数:使用
async和await处理异步操作
通过合理使用这些函数特性,你可以编写更清晰、更类型安全的 TypeScript 代码。