TypeScript 函数
最后修改于 2025 年 2 月 24 日
TypeScript 中的函数通过精确的类型注解封装可重用代码块,确保代码的健壮性和可预测性。它们通过引入参数类型、返回类型和高级模式,扩展了 JavaScript 函数的功能。通过定义输入和输出的类型,TypeScript 函数减少了运行时错误的可能性,并提高了代码的可读性和可维护性。
主要优势
- 类型注解:通过显式定义参数和返回值的类型,TypeScript 函数有助于在编译时捕获与类型相关的错误,从而实现更可预测的代码执行。
- IntelliSense 支持:TypeScript 在 IDE 中提供增强的 IntelliSense,为函数参数和返回类型提供自动补全和文档,提高开发效率。
- 函数重载:TypeScript 支持函数重载,允许为单个函数名称创建多个函数签名,从而增强了处理不同场景的灵活性。
基本函数语法
TypeScript 函数使用类型注解来定义参数和返回值。此示例使用显式类型计算矩形的面积。
function getRectangleArea(length: number, width: number): number {
return length * width;
}
console.log(getRectangleArea(8, 5)); // Output: 40
getRectangleArea 函数接受两个参数:length 和 width,两者都定义为 number 类型。它返回它们的乘积,并显式定义为 number 类型。TypeScript 确保只传入和返回数字。
调用 getRectangleArea("8", 5) 将因类型不匹配而在编译时失败。输出 40 证实了计算结果。这表明类型注解如何为基本函数强制执行安全性和清晰性。
函数表达式
函数表达式将函数分配给带有类型注解的变量。此示例使用类型化的变量格式化用户 ID。
const generateUserId: (prefix: string, id: number) => string =
function(prefix, id) {
return `${prefix}-${id.toString().padStart(4, '0')}`;
};
console.log(generateUserId("USR", 42)); // Output: USR-0042
generateUserId 变量的类型是接受 string 和 number、返回 string 的函数。该函数以零填充 ID 以保持一致性。
TypeScript 会推断函数体内的参数类型,避免冗余。传入 42, "USR" 将因类型不匹配而报错。输出 "USR-0042" 显示了格式化的结果。此模式对于具有显式类型安全性的命名函数赋值非常有用。
箭头函数
箭头函数提供简洁的语法和完整的类型支持。此示例使用箭头函数计算圆的周长。
const getCircumference = (radius: number): number =>
2 * Math.PI * radius;
console.log(getCircumference(3)); // Output: 18.84955592153876
getCircumference 箭头函数接受一个 number 类型的 radius 并返回一个 number。它使用 Math.PI 来精确计算。
TypeScript 允许省略可推断的返回类型,但此处为了清晰起见将其包含在内。传入像 "3" 这样的字符串会失败。输出约 18.85 证实了结果。箭头函数非常适合简洁、类型安全的表达式。
匿名函数
匿名函数没有名称,通常内联使用。此示例使用匿名函数作为回调来过滤数组。
const numbers: number[] = [1, 2, 3, 4, 5, 6];
const odds = numbers.filter(function(value: number): boolean {
return value % 2 !== 0;
});
console.log(odds); // Output: [1, 3, 5]
filter 内的匿名函数接受一个 number 类型的 value 并返回一个 boolean。它检查数字是否为奇数。
TypeScript 从 numbers 是 number[] 的上下文中推断类型,但显式类型可以增加清晰度。输出 [1, 3, 5] 显示了奇数。匿名函数对于一次性逻辑非常方便。
可选参数
可选参数用 ? 标记,允许在函数调用中具有灵活性。此示例使用可选的问候语构建消息。
function buildMessage(name: string, greeting?: string): string {
return greeting ? `${greeting}, ${name}!` : `Hi, ${name}!`;
}
console.log(buildMessage("Emma", "Hello")); // Output: Hello, Emma!
console.log(buildMessage("Liam")); // Output: Hi, Liam!
buildMessage 函数需要 name,但使用 ? 使 greeting 可选。如果 greeting 未定义,它将使用三元运算符默认为 "Hi"。
TypeScript 确保 greeting(如果提供)是 string 类型。省略它是有效的,而传入数字将报错。输出显示了两种情况:"Hello, Emma!" 和 "Hi, Liam!"。这对于带有可选输入的自定义函数很有用。
默认参数
默认参数在省略参数时提供备用值。此示例使用默认费率计算折扣价。
function calculateDiscountedPrice(price: number, rate: number = 0.15): number {
return price * (1 - rate);
}
console.log(calculateDiscountedPrice(200)); // Output: 170
console.log(calculateDiscountedPrice(200, 0.25)); // Output: 150
calculateDiscountedPrice 函数默认将 rate 设置为 0.15。它将折扣应用于 price,并返回一个 number。TypeScript 从默认值推断 rate 为 number。
使用一个参数调用它会使用默认值,而使用两个参数则会覆盖默认值。传入像 "0.15" 这样的字符串会失败。输出为 170(便宜 15%)和 150(便宜 25%)。这简化了带有常见默认值的函数调用。
剩余参数
剩余参数将可变数量的参数收集到一个类型化的数组中。此示例计算平均成绩列表。
function averageGrades(...grades: number[]): number {
const sum = grades.reduce((acc, grade) => acc + grade, 0);
return grades.length ? sum / grades.length : 0;
}
console.log(averageGrades(88, 92, 76, 95)); // Output: 87.75
averageGrades 函数使用 ...grades 将数字收集到 number[] 中。它计算平均值,并使用 0 作为备用值来处理空情况。
TypeScript 强制所有参数都是数字——传入像 "90" 这样的字符串会报错。输出 87.75 是四门成绩的平均值。剩余参数对于具有可变数量输入的函数非常有用。
函数重载
函数重载为单个实现定义了多个签名。此示例以不同的方式处理不同的输入类型。
function transformValue(value: string): string;
function transformValue(value: number): number;
function transformValue(value: string | number): string | number {
return typeof value === "string" ? value.repeat(2) : value + 10;
}
console.log(transformValue("Hi")); // Output: HiHi
console.log(transformValue(5)); // Output: 15
transformValue 函数有两个重载签名:一个用于 string 返回 string,一个用于 number 返回 number。该实现使用联合类型处理两者,重复字符串或为数字加 10。
TypeScript 确保调用匹配签名——transformValue(true) 将失败。输出为 "HiHi"(字符串重复)和 15(数字增加)。重载精简了多类型函数的类型检查。
泛型函数
泛型函数使用类型参数来实现可重用逻辑。此示例交换任意类型的两个值。
function swap<T>(a: T, b: T): [T, T] {
return [b, a];
}
console.log(swap<number>(10, 20)); // Output: [20, 10]
console.log(swap<string>("a", "b")); // Output: ["b", "a"]
swap 函数使用泛型类型 T 作为其参数和返回元组。它适用于任何类型,由 TypeScript 显式指定或推断。
使用 number 和 string 的调用产生 [20, 10] 和 ["b", "a"]。混合类型如 swap(10, "a") 因类型不匹配而报错。泛型支持灵活、类型安全的重用函数。
函数类型别名
类型别名定义可重用的函数签名。此示例将别名用于回调。
type FilterCallback = (value: number, index: number) => boolean;
function filterNumbers(arr: number[], callback: FilterCallback): number[] {
return arr.filter(callback);
}
const evens = filterNumbers([1, 2, 3, 4], (n) => n % 2 === 0);
console.log(evens); // Output: [2, 4]
FilterCallback 别名定义了一个函数类型,该类型接受 number 和 index,并返回 boolean。filterNumbers 函数将其用于回调参数。
回调过滤偶数,产生 [2, 4]。像 (n: string) => true 这样的回调将因类型不匹配而报错。这种方法确保了跨用例的函数签名一致性。
异步函数
异步函数返回带有类型化结果的 Promise。此示例异步获取用户名。
async function fetchUserName(id: number): Promise<string> {
const response = await Promise.resolve(`User${id}`);
return response;
}
(async () => {
const name = await fetchUserName(1);
console.log(name); // Output: User1
})();
fetchUserName 函数是异步的,返回一个 Promise。它使用 Promise.resolve 模拟获取,并解析为字符串。
IIFE 等待结果,并记录 "User1"。返回一个数字将因 Promise 类型而报错。异步函数是类型化异步操作的关键。
生成器函数
生成器函数使用 function* 语法惰性地生成值。此示例生成一个斐波那契数列。
function* fibonacciSequence(limit: number): Generator{ let a = 0, b = 1; for (let i = 0; i < limit; i++) { yield a; [a, b] = [b, a + b]; } } const fib = fibonacciSequence(5); console.log([...fib]); // Output: [0, 1, 1, 2, 3]
fibonacciSequence 函数是一个生成器,类型为 Generator。它生成直到 limit 的数字,使用循环计算斐波那契值。
每次 yield 都会暂停执行,返回当前值。展开运算符将前 5 个值收集为 [0, 1, 1, 2, 3]。TypeScript 确保生成的都是数字,增强了类型安全性。
最佳实践
- 显式定义返回类型:为复杂函数使用显式返回类型以获得清晰性。
- 专注于单一职责:确保每个函数执行一项清晰的任务。
- 最小化参数数量:将参数保持在 4 个以下;对于更多输入使用对象。
- 优先使用箭头函数:对回调使用箭头函数,以实现简洁性和一致的
this绑定。 - 强制类型安全:验证参数类型并处理
null等边缘情况。 - 明智地使用泛型:为可重用逻辑应用泛型,避免过度复杂化。
- 利用类型别名:使用别名定义函数签名以实现可重用性。
来源
本教程通过实际示例介绍了 TypeScript 函数。实现这些模式可以编写更安全、更易于维护的代码。