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); // 类型安全
注意事项
- 始终为函数参数添加类型注解——这是 TypeScript 最基本的类型检查
- 可选参数使用
?标记,不要使用默认值来表示可选 - 函数重载的签名数量不要过多——超过 5 个时考虑使用联合类型
- 箭头函数没有自己的
this——在类中使用箭头函数可以避免this绑定问题 - 回调函数的返回值——事件处理函数通常返回
void