函数是 TypeScript 中最常用的组件。本章学习如何为函数添加完善的类型。
3.1 函数参数和返回值类型
// 基本写法:参数类型 + 返回值类型
function add(a: number, b: number): number {
return a + b;
}
// 箭头函数
const multiply = (a: number, b: number): number => a * b;
// 返回值可以被推断,不一定要写
function greet(name: string) {
return `Hello, ${name}!`; // TS 自动推断返回 string
}
💡 函数参数类型必须写,返回值类型通常可以省略(TS 会自动推断),但公开的 API 建议写上。
3.2 可选参数
用 ? 标记可选参数,可选参数必须在必选参数后面:
function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return `${firstName} ${lastName}`;
}
return firstName;
}
buildName("张"); // ✅ "张"
buildName("张", "三"); // ✅ "张 三"
buildName(); // ❌ 至少需要 1 个参数
3.3 默认参数
function createUser(name: string, role: string = "user"): void {
console.log(`${name} is a ${role}`);
}
createUser("张三"); // "张三 is a user"
createUser("李四", "admin"); // "李四 is a admin"
💡 有默认值的参数不需要
?,TypeScript 会自动将其视为可选。
3.4 剩余参数(Rest Parameters)
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
// 结合必选参数
function log(level: string, ...messages: string[]): void {
console.log(`[${level}]`, ...messages);
}
log("INFO", "Server started", "Port: 3000");
3.5 函数类型表达式
可以用 type 或 interface 单独定义函数的类型:
// type 方式(推荐)
type MathFunc = (a: number, b: number) => number;
const add: MathFunc = (a, b) => a + b; // 参数类型从 MathFunc 推断
const subtract: MathFunc = (a, b) => a - b;
// 作为参数类型
function calculate(a: number, b: number, operation: MathFunc): number {
return operation(a, b);
}
calculate(10, 5, add); // 15
calculate(10, 5, subtract); // 5
回调函数类型
type EventHandler = (event: { type: string; target: any }) => void;
function addEventListener(type: string, handler: EventHandler): void {
// ...
}
addEventListener("click", (event) => {
console.log(event.type); // TS 知道 event 的结构
});
3.6 函数重载
当函数根据不同参数返回不同类型时,使用重载:
// 重载签名(声明有哪些调用方式)
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();
} else if (typeof value === "number") {
return value.toFixed(2);
} else {
return value.toISOString();
}
}
format("hello "); // ✅ string
format(3.14159); // ✅ string
format(new Date()); // ✅ string
format(true); // ❌ 没有匹配的重载
更精确的重载
// 根据输入类型返回不同类型
function parse(input: string): object;
function parse(input: string, asArray: true): any[];
function parse(input: string, asArray?: boolean): object | any[] {
const result = JSON.parse(input);
if (asArray) return Array.isArray(result) ? result : [result];
return result;
}
const obj = parse('{"a":1}'); // 类型是 object
const arr = parse('[1,2,3]', true); // 类型是 any[]
💡 很多时候,联合类型或泛型可以替代重载,代码更简洁。重载适合参数和返回值有对应关系的场景。
3.7 this 类型
interface User {
name: string;
greet(this: User): string; // 显式声明 this 的类型
}
const user: User = {
name: "张三",
greet() {
return `Hello, ${this.name}`; // this 被推断为 User
},
};
user.greet(); // ✅
const fn = user.greet;
fn(); // ❌ this 上下文不对
3.8 泛型函数(预览)
函数可以接受"类型参数",让它适用于多种类型:
// 不用泛型:要么用 any(不安全),要么写多个函数
function firstAny(arr: any[]): any {
return arr[0];
}
// 用泛型:安全且灵活
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
first([1, 2, 3]); // 返回类型:number
first(["a", "b", "c"]); // 返回类型:string
first<boolean>([true]); // 显式指定类型参数
📖 泛型将在第 5 章详细讲解。
3.9 常见函数类型模式
异步函数
async function fetchUser(id: number): Promise<User> {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
// 类型定义
type AsyncFn<T> = () => Promise<T>;
构造签名
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
返回 void vs undefined
// void:表示不关心返回值
type VoidFunc = () => void;
const f1: VoidFunc = () => { return true; }; // ✅ 允许!返回值被忽略
const result = f1(); // result 类型是 void,不能当 boolean 用
// undefined:必须明确返回 undefined
type UndefFunc = () => undefined;
const f2: UndefFunc = () => { return true; }; // ❌ 不能返回 boolean
📝 练习
- 写一个函数
repeat(str: string, times?: number),返回重复后的字符串,times 默认为 2 - 写一个带剩余参数的
joinWith(separator: string, ...parts: string[]) - 用函数重载实现
toNumber:传入 string 返回 number,传入 string[] 返回 number[] - 定义一个回调类型
Comparator<T>,然后实现排序函数
// 参考答案
// 1
function repeat(str: string, times: number = 2): string {
return str.repeat(times);
}
// 2
function joinWith(separator: string, ...parts: string[]): string {
return parts.join(separator);
}
joinWith("-", "a", "b", "c"); // "a-b-c"
// 3
function toNumber(value: string): number;
function toNumber(value: string[]): number[];
function toNumber(value: string | string[]): number | number[] {
if (Array.isArray(value)) {
return value.map(Number);
}
return Number(value);
}
// 4
type Comparator<T> = (a: T, b: T) => number;
function sort<T>(arr: T[], compare: Comparator<T>): T[] {
return [...arr].sort(compare);
}
sort([3, 1, 2], (a, b) => a - b); // [1, 2, 3]