

在任何编程语言中，函数都是构建逻辑的基本单元。它们帮助我们封装代码、实现复用并构建复杂的应用。当我们进入 TypeScript 的世界，函数的能力得到了进一步的增强——这主要归功于其强大的类型系统。

在日常开发中，为函数精确定义输入和输出是保障代码健壮性的关键。接下来，我们将一起探讨 TypeScript 是如何通过类型注解、可选参数和默认参数，来优化函数定义的。

### 为函数添加类型注解

在 TypeScript 中，最直接的增强是为函数的参数和返回值添加明确的类型注解。这不仅是 TypeScript 的核心特性，也是编写高质量、可维护代码的基石。

它的语法非常直观：

*   在参数名后使用冒号 `(:)` 来指定该参数的类型。
*   在函数参数列表的括号后使用冒号 `(:)` 来指定函数的返回值类型。

让我们来看一个简单的例子。假设我们需要一个函数，它接收两个数字作为参数，并返回它们的和。

```typescript
function add(a: number, b: number): number {
  return a + b;
}
```

通过这种方式，我们向 TypeScript 编译器以及其他开发者清晰地传达了此函数的“契约”：

1.  参数 `a` 必须是 `number` 类型。
2.  参数 `b` 必须是 `number` 类型。
3.  该函数必须返回一个 `number` 类型的值。

如果我们在调用 `add` 函数时传入了非数字类型的参数，TypeScript 编译器会在编译阶段就立刻抛出错误，从而避免了在运行时可能出现的意外行为。这种“前置”的错误捕获机制，是 TypeScript 相比于原生 JavaScript 的一大优势。

### 赋予函数更多灵活性：可选参数与默认参数

虽然严格的类型定义是好事，但在某些场景下，我们也需要函数具备一定的灵活性。例如，一个函数的某些参数并非每次调用都需要传递。针对这种情况，TypeScript 提供了可选参数和默认参数两种实用的机制。

#### 1. 可选参数

当我们希望函数的某个参数可以被“省略”时，可以使用可选参数。语法是在参数名后、冒号前添加一个问号 `(?)`。

我们来设想一个向用户打招呼的函数。这个函数必须知道用户的名字，但问候语可以是可选的。

```typescript
function greet(name: string, salutation?: string): string {
  if (salutation) {
    return `${salutation}, ${name}!`;
  } else {
    return `Hello, ${name}!`;
  }
}

// 两种有效的调用方式
console.log(greet("Alice")); // 输出: Hello, Alice!
console.log(greet("Bob", "Good morning")); // 输出: Good morning, Bob!
```

需要注意的是，当一个可选参数未被传递时，它在函数内部的值是 `undefined`。因此，我们需要在函数体内进行相应的逻辑判断。

此外，一个重要的规则是：**可选参数必须位于必选参数之后**。这是为了让 TypeScript 能够正确地将传入的参数与函数定义中的参数对应起来。

#### 2. 默认参数

默认参数与可选参数解决的是类似的问题，但实现方式略有不同。它允许我们为参数提供一个默认值，当调用者没有传递该参数时，函数将自动使用这个预设的值。

语法非常简洁，直接在参数声明后使用等号 `(=)` 即可。

我们来重构一下上面的 `greet` 函数，这次使用默认参数：

```typescript
function greetWithDefault(name: string, salutation: string = "Hello"): string {
  return `${salutation}, ${name}!`;
}

// 两种调用方式及其结果
console.log(greetWithDefault("Alice")); // 输出: Hello, Alice!
console.log(greetWithDefault("Bob", "Good morning")); // 输出: Good morning, Bob!
```

使用默认参数的好处是代码更显简洁。我们不再需要在函数体内检查参数是否为 `undefined`，因为 TypeScript 已经保证了 `salutation` 参数总会有一个 `string` 类型的值。

当一个参数被赋予了默认值，它实际上也变成了“可选”的。与可选参数不同的是，带有默认值的参数不强制要求必须放在参数列表的末尾。然而，为了保持代码的可读性和一致性，通常我们还是建议将它们放在必选参数之后。

### 总结

通过本次梳理，我们可以看到 TypeScript 为函数带来了显著的改进：

*   **类型注解**：通过为参数和返回值添加类型，我们极大地提升了代码的明确性和可靠性，能在开发早期就发现潜在的类型错误。
*   **可选参数 `(?)`**：提供了定义非必需参数的灵活性，调用时可以省略这些参数。
*   **默认参数 `(=)`**：在参数未传递时为其提供预设值，简化了函数内部的逻辑处理，并使代码更加清晰。

掌握这些特性，是编写现代化、高健壮性 TypeScript 代码的基础。在日常开发中，结合运用这些工具，我们可以构建出既灵活又安全的函数，从而为整个应用的质量提供坚实的保障。

