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 函数。实现这些模式可以编写更安全、更易于维护的代码。