ZetCode

TypeScript 函数

最后修改于 2025 年 2 月 24 日

TypeScript 中的函数通过精确的类型注解封装可重用代码块,确保代码的健壮性和可预测性。它们通过引入参数类型、返回类型和高级模式,扩展了 JavaScript 函数的功能。通过定义输入和输出的类型,TypeScript 函数减少了运行时错误的可能性,并提高了代码的可读性和可维护性。

主要优势

基本函数语法

TypeScript 函数使用类型注解来定义参数和返回值。此示例使用显式类型计算矩形的面积。

basic_function.ts
function getRectangleArea(length: number, width: number): number {
    return length * width;
}

console.log(getRectangleArea(8, 5)); // Output: 40

getRectangleArea 函数接受两个参数:lengthwidth,两者都定义为 number 类型。它返回它们的乘积,并显式定义为 number 类型。TypeScript 确保只传入和返回数字。

调用 getRectangleArea("8", 5) 将因类型不匹配而在编译时失败。输出 40 证实了计算结果。这表明类型注解如何为基本函数强制执行安全性和清晰性。

函数表达式

函数表达式将函数分配给带有类型注解的变量。此示例使用类型化的变量格式化用户 ID。

function_expression.ts
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 变量的类型是接受 stringnumber、返回 string 的函数。该函数以零填充 ID 以保持一致性。

TypeScript 会推断函数体内的参数类型,避免冗余。传入 42, "USR" 将因类型不匹配而报错。输出 "USR-0042" 显示了格式化的结果。此模式对于具有显式类型安全性的命名函数赋值非常有用。

箭头函数

箭头函数提供简洁的语法和完整的类型支持。此示例使用箭头函数计算圆的周长。

arrow_function.ts
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 证实了结果。箭头函数非常适合简洁、类型安全的表达式。

匿名函数

匿名函数没有名称,通常内联使用。此示例使用匿名函数作为回调来过滤数组。

anonymous_function.ts
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 从 numbersnumber[] 的上下文中推断类型,但显式类型可以增加清晰度。输出 [1, 3, 5] 显示了奇数。匿名函数对于一次性逻辑非常方便。

可选参数

可选参数用 ? 标记,允许在函数调用中具有灵活性。此示例使用可选的问候语构建消息。

optional_params.ts
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!"。这对于带有可选输入的自定义函数很有用。

默认参数

默认参数在省略参数时提供备用值。此示例使用默认费率计算折扣价。

default_params.ts
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 从默认值推断 ratenumber

使用一个参数调用它会使用默认值,而使用两个参数则会覆盖默认值。传入像 "0.15" 这样的字符串会失败。输出为 170(便宜 15%)和 150(便宜 25%)。这简化了带有常见默认值的函数调用。

剩余参数

剩余参数将可变数量的参数收集到一个类型化的数组中。此示例计算平均成绩列表。

rest_params.ts
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_overload.ts
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(数字增加)。重载精简了多类型函数的类型检查。

泛型函数

泛型函数使用类型参数来实现可重用逻辑。此示例交换任意类型的两个值。

generic_function.ts
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 显式指定或推断。

使用 numberstring 的调用产生 [20, 10] 和 ["b", "a"]。混合类型如 swap(10, "a") 因类型不匹配而报错。泛型支持灵活、类型安全的重用函数。

函数类型别名

类型别名定义可重用的函数签名。此示例将别名用于回调。

type_alias_function.ts
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 别名定义了一个函数类型,该类型接受 numberindex,并返回 booleanfilterNumbers 函数将其用于回调参数。

回调过滤偶数,产生 [2, 4]。像 (n: string) => true 这样的回调将因类型不匹配而报错。这种方法确保了跨用例的函数签名一致性。

异步函数

异步函数返回带有类型化结果的 Promise。此示例异步获取用户名。

async_function.ts
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* 语法惰性地生成值。此示例生成一个斐波那契数列。

generator_function.ts
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 确保生成的都是数字,增强了类型安全性。

最佳实践

来源

TypeScript 函数文档

本教程通过实际示例介绍了 TypeScript 函数。实现这些模式可以编写更安全、更易于维护的代码。

作者

我叫 Jan Bodnar,是一位热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 TypeScript 教程