强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

TypeScript 开发指南 / 04 - 函数

函数

函数是 TypeScript 中最重要的抽象单元。TypeScript 为 JavaScript 的函数添加了丰富的类型支持。

函数类型注解

基本语法

// 参数类型 + 返回值类型
function add(a: number, b: number): number {
  return a + b;
}

// 箭头函数
const multiply = (a: number, b: number): number => a * b;

// 函数表达式
const divide = function(a: number, b: number): number {
  return a / b;
};

参数类型

// 必选参数
function greet(name: string): string {
  return `Hello, ${name}!`;
}

// 可选参数(使用 ?)
function greet(name: string, title?: string): string {
  if (title) {
    return `Hello, ${title} ${name}!`;
  }
  return `Hello, ${name}!`;
}

greet("Alice");           // ✅ "Hello, Alice!"
greet("Alice", "Dr.");    // ✅ "Hello, Dr. Alice!"

// 默认参数
function greet(name: string, greeting: string = "Hello"): string {
  return `${greeting}, ${name}!`;
}

greet("Alice");              // ✅ "Hello, Alice!"
greet("Alice", "Hi");        // ✅ "Hi, Alice!"

注意:可选参数必须放在必选参数之后。function f(a?: number, b: string) 是错误的。

返回值类型

// 显式返回值类型(推荐)
function getUser(id: number): User {
  return database.find(id);
}

// 返回值类型推断(简单函数可以省略)
function add(a: number, b: number) {
  return a + b; // 推断为 number
}

// 返回 void
function log(message: string): void {
  console.log(message);
}

// 返回 never
function throwError(msg: string): never {
  throw new Error(msg);
}

// 返回 Promise
async function fetchData(url: string): Promise<Response> {
  return await fetch(url);
}

函数类型

类型别名定义函数类型

// 定义函数类型
type MathOperation = (a: number, b: number) => number;

// 使用函数类型
const add: MathOperation = (a, b) => a + b;
const subtract: MathOperation = (a, b) => a - b;
const multiply: MathOperation = (a, b) => a * b;

// 函数类型作为参数
function calculate(a: number, b: number, operation: MathOperation): number {
  return operation(a, b);
}

calculate(10, 5, add);      // 15
calculate(10, 5, subtract); // 5

接口定义函数类型

// 使用接口定义函数类型
interface SearchFunc {
  (source: string, query: string): boolean;
}

const search: SearchFunc = (source, query) => {
  return source.includes(query);
};

调用签名和构造签名

// 调用签名
interface Logger {
  (message: string): void;
  level: number;
  setLevel(level: number): void;
}

// 构造签名
interface UserConstructor {
  new (name: string, age: number): User;
}

函数重载(Function Overloading)

函数重载允许一个函数接受不同类型的参数并返回不同类型的结果:

// 重载签名(声明)
function format(value: string): string;
function format(value: number): string;
function format(value: Date): string;

// 实现签名
function format(value: string | number | Date): string {
  if (typeof value === "string") {
    return value.trim();
  }
  if (typeof value === "number") {
    return value.toFixed(2);
  }
  return value.toISOString();
}

format("hello ");     // ✅ "hello"
format(3.14159);       // ✅ "3.14"
format(new Date());    // ✅ "2026-05-10T..."

复杂重载示例

// 根据参数数量返回不同类型
function createElement(tag: string): HTMLElement;
function createElement(tag: string, attrs: Record<string, string>): HTMLElement;
function createElement(
  tag: string,
  attrs?: Record<string, string>,
  ...children: string[]
): HTMLElement;

function createElement(
  tag: string,
  attrs?: Record<string, string>,
  ...children: string[]
): HTMLElement {
  const el = document.createElement(tag);
  if (attrs) {
    Object.entries(attrs).forEach(([key, value]) => {
      el.setAttribute(key, value);
    });
  }
  children.forEach(child => {
    el.appendChild(document.createTextNode(child));
  });
  return el;
}

createElement("div");                            // ✅
createElement("div", { class: "container" });    // ✅
createElement("div", { id: "app" }, "Hello");    // ✅

rest 参数(剩余参数)

// 基本 rest 参数
function sum(...numbers: number[]): number {
  return numbers.reduce((total, n) => total + n, 0);
}

sum(1, 2, 3);      // 6
sum(1, 2, 3, 4, 5); // 15

// 固定参数 + rest 参数
function log(level: string, ...messages: string[]): void {
  console.log(`[${level}]`, ...messages);
}

log("INFO", "Server started", "on port 3000");

元组类型 rest 参数

// 使用元组类型精确描述参数
function fetchData(
  url: string,
  options: {
    method: "GET" | "POST";
    headers?: Record<string, string>;
  }
): Promise<Response> {
  return fetch(url, options);
}

// 元组 + rest 参数
type Args = [string, number, boolean];

function processArgs(...args: Args): void {
  const [name, age, active] = args;
  console.log(name, age, active);
}

this 关键字

JavaScript 的 this 是动态绑定的,TypeScript 提供了静态类型检查:

显式 this 参数

// 使用 this 参数声明 this 的类型
interface User {
  name: string;
  greet(this: User): string;
}

const user: User = {
  name: "Alice",
  greet() {
    return `Hello, I'm ${this.name}`;
  }
};

// this 参数不会出现在运行时参数中
user.greet(); // "Hello, I'm Alice"

this 在类中的使用

class Counter {
  private count: number = 0;

  // 普通方法中 this 指向实例
  increment(): this {
    this.count++;
    return this; // 支持链式调用
  }

  // 箭头函数捕获外部 this
  getCount = (): number => {
    return this.count;
  };
}

const counter = new Counter();
counter.increment().increment().increment();
console.log(counter.getCount()); // 3

常见 this 陷阱

class Button {
  label: string = "Click";

  // ❌ 问题:this 在回调中丢失
  bindClick() {
    document.addEventListener("click", function() {
      console.log(this.label); // this 是 undefined 或 window
    });
  }

  // ✅ 方案1:箭头函数
  bindClickFixed1() {
    document.addEventListener("click", () => {
      console.log(this.label); // 正确
    });
  }

  // ✅ 方案2:bind
  bindClickFixed2() {
    document.addEventListener("click", this.handleClick.bind(this));
  }

  handleClick() {
    console.log(this.label);
  }
}

回调函数类型

// 事件回调
type EventHandler<T> = (event: T) => void;

interface EventEmitter<T> {
  on(event: string, handler: EventHandler<T>): void;
  off(event: string, handler: EventHandler<T>): void;
  emit(event: string, data: T): void;
}

// 异步回调
type AsyncCallback<T> = (error: Error | null, result?: T) => void;

function readFile(path: string, callback: AsyncCallback<string>): void {
  // ...
}

// Node.js 风格的回调
readFile("/path/to/file", (error, data) => {
  if (error) {
    console.error(error);
    return;
  }
  console.log(data);
});

高阶函数

// 返回函数的函数
function createMultiplier(factor: number): (x: number) => number {
  return (x) => x * factor;
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5));  // 10
console.log(triple(5));  // 15

// 装饰器模式
function withLogging<T extends (...args: any[]) => any>(
  fn: T
): (...args: Parameters<T>) => ReturnType<T> {
  return (...args) => {
    console.log(`调用函数,参数:`, args);
    const result = fn(...args);
    console.log(`返回值:`, result);
    return result;
  };
}

const loggedAdd = withLogging((a: number, b: number) => a + b);
loggedAdd(1, 2);
// 输出:调用函数,参数: [1, 2]
// 输出:返回值: 3

函数参数的高级模式

解构参数

// 解构对象参数
function createServer({
  host = "localhost",
  port = 3000,
  ssl = false
}: ServerConfig): Server {
  // ...
}

interface ServerConfig {
  host?: string;
  port?: number;
  ssl?: boolean;
}

createServer({ port: 8080 });

参数默认值 + 类型

// 带默认值的参数类型
function paginate(
  items: number[],
  page: number = 1,
  pageSize: number = 10
): number[] {
  const start = (page - 1) * pageSize;
  return items.slice(start, start + pageSize);
}

函数重载 + 泛型

// 泛型函数重载
function pick<T, K extends keyof T>(obj: T, key: K): T[K];
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;

function pick(obj: any, keys: any): any {
  if (typeof keys === "string") {
    return obj[keys];
  }
  return keys.reduce((result: any, key: string) => {
    result[key] = obj[key];
    return result;
  }, {});
}

业务场景:API 请求函数

// 类型安全的 API 请求封装
interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

interface User {
  id: number;
  name: string;
  email: string;
}

// 泛型请求函数
async function apiGet<T>(url: string): Promise<ApiResponse<T>> {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }
  return response.json();
}

// 使用
const result = await apiGet<User>("/api/user/1");
console.log(result.data.name); // 类型安全

注意事项

  1. 始终为函数参数添加类型注解——这是 TypeScript 最基本的类型检查
  2. 可选参数使用 ? 标记,不要使用默认值来表示可选
  3. 函数重载的签名数量不要过多——超过 5 个时考虑使用联合类型
  4. 箭头函数没有自己的 this——在类中使用箭头函数可以避免 this 绑定问题
  5. 回调函数的返回值——事件处理函数通常返回 void

扩展阅读