Skip to content

函数类型

函数是 JavaScript 的核心。TypeScript 为函数提供了完整的类型支持,包括参数类型、返回值类型、可选参数、函数重载等特性。

函数类型基础#

参数和返回值类型#

// TypeScript 5.x
// 函数声明
function add(a: number, b: number): number {
return a + b
}
// 箭头函数
const multiply = (a: number, b: number): number => {
return a * b
}
// 简写(单表达式)
const divide = (a: number, b: number): number => a / b
// 无返回值使用 void
function log(message: string): void {
console.log(message)
}

返回值类型推断#

TypeScript 可以自动推断返回值类型:

// 自动推断返回值为 number
function add(a: number, b: number) {
return a + b
}
// 自动推断返回值为 string
function greet(name: string) {
return `Hello, ${name}!`
}
// 🔶 建议:公共 API 显式标注返回值,内部函数可以依赖推断
export function calculateTotal(prices: number[]): number {
return prices.reduce((sum, price) => sum + price, 0)
}

函数类型表达式#

可以单独定义函数的类型:

// 函数类型表达式
type AddFunction = (a: number, b: number) => number
const add: AddFunction = (a, b) => a + b
// 作为参数类型
function calculate(
fn: (x: number, y: number) => number,
a: number,
b: number
): number {
return fn(a, b)
}
calculate(add, 10, 5) // 15
calculate((x, y) => x - y, 10, 5) // 5

完整的函数类型#

// 使用 type 定义
type GreetFunction = (name: string, greeting?: string) => string
// 使用 interface 定义(调用签名)
interface GreetInterface {
(name: string, greeting?: string): string
}
const greet: GreetFunction = (name, greeting = 'Hello') => {
return `${greeting}, ${name}!`
}

可选参数#

使用 ? 标记可选参数:

function greet(name: string, title?: string): string {
if (title) {
return `${title} ${name}`
}
return name
}
greet('张三') // "张三"
greet('张三', '博士') // "博士 张三"

🔶 可选参数必须放在必需参数之后:

// ❌ 错误:可选参数不能在必需参数之前
// function wrong(a?: number, b: number) {}
// ✅ 正确
function correct(a: number, b?: number) {}

可选参数的类型是 T | undefined

function example(value?: string) {
// value 的类型是 string | undefined
console.log(value?.toUpperCase()) // 需要安全访问
}

默认参数#

默认参数会自动推断类型,且不需要 ?

function greet(name: string, greeting: string = 'Hello'): string {
return `${greeting}, ${name}!`
}
greet('张三') // "Hello, 张三!"
greet('张三', '你好') // "你好, 张三!"
// 默认参数可以放在前面(但调用时需要传 undefined)
function example(first: number = 10, second: number): number {
return first + second
}
example(undefined, 5) // 15

默认参数 vs 可选参数#

// 可选参数:值可能是 undefined
function fn1(x?: number) {
console.log(x) // number | undefined
}
// 默认参数:始终有值
function fn2(x: number = 10) {
console.log(x) // number
}
fn1() // undefined
fn2() // 10

剩余参数#

使用 ... 收集剩余参数:

// 剩余参数是数组类型
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(prefix: string, ...messages: string[]): void {
messages.forEach((msg) => console.log(`${prefix}: ${msg}`))
}
log('INFO', '开始处理', '处理完成')

剩余参数与元组#

// 使用元组类型限制剩余参数
function format(...args: [string, number, boolean]): string {
const [name, age, active] = args
return `${name}, ${age}岁, ${active ? '活跃' : '不活跃'}`
}
format('张三', 25, true) // "张三, 25岁, 活跃"
// 带可变部分的元组
function mixed(first: string, ...rest: [number, ...boolean[]]): void {
console.log(first, rest)
}
mixed('hello', 1, true, false, true)

函数重载#

当函数根据不同参数有不同返回类型时,使用函数重载:

// 重载签名
function parse(input: string): number
function parse(input: number): string
function parse(input: boolean): string
// 实现签名
function parse(input: string | number | boolean): number | string {
if (typeof input === 'string') {
return parseInt(input, 10)
} else if (typeof input === 'number') {
return input.toString()
} else {
return input ? 'true' : 'false'
}
}
// 调用时有精确的类型
const num = parse('123') // number
const str = parse(456) // string
const bool = parse(true) // string

更复杂的重载示例#

// 根据参数数量有不同行为
function createElement(tag: 'div'): HTMLDivElement
function createElement(tag: 'span'): HTMLSpanElement
function createElement(tag: 'input'): HTMLInputElement
function createElement(tag: string): HTMLElement
function createElement(tag: string): HTMLElement {
return document.createElement(tag)
}
const div = createElement('div') // HTMLDivElement
const input = createElement('input') // HTMLInputElement
const custom = createElement('custom-element') // HTMLElement

🔶 重载注意事项:

// 重载签名的顺序很重要:更具体的放前面
function process(x: string): string // 更具体
function process(x: unknown): unknown // 更宽泛
function process(x: unknown): unknown {
if (typeof x === 'string') {
return x.toUpperCase()
}
return x
}
// TypeScript 按顺序匹配,第一个匹配的类型生效
process('hello') // 返回类型是 string
process(123) // 返回类型是 unknown

this 类型#

在方法中可以显式声明 this 的类型:

interface User {
name: string
greet(this: User): string
}
const user: User = {
name: '张三',
greet() {
return `Hello, ${this.name}`
},
}
user.greet() // "Hello, 张三"
// 单独调用会报错(this 类型不匹配)
// const fn = user.greet;
// fn(); // ❌ 错误

this 参数#

function onClick(this: HTMLButtonElement, event: Event) {
console.log(this.textContent) // this 是 HTMLButtonElement
}
const button = document.querySelector('button')!
button.addEventListener('click', onClick)

回调函数类型#

// 定义回调类型
type Callback = (error: Error | null, result?: string) => void
function fetchData(url: string, callback: Callback): void {
try {
// 模拟异步操作
setTimeout(() => {
callback(null, 'data')
}, 1000)
} catch (err) {
callback(err as Error)
}
}
fetchData('/api/data', (err, result) => {
if (err) {
console.error(err)
return
}
console.log(result)
})

常见回调模式#

// 事件处理器
type EventHandler<T = Event> = (event: T) => void
// 比较函数
type Comparator<T> = (a: T, b: T) => number
// 转换函数
type Mapper<T, U> = (item: T, index: number) => U
// 谓词函数
type Predicate<T> = (item: T) => boolean
// 使用示例
const numbers = [3, 1, 4, 1, 5, 9]
const isEven: Predicate<number> = (n) => n % 2 === 0
const double: Mapper<number, number> = (n) => n * 2
const compare: Comparator<number> = (a, b) => a - b
numbers.filter(isEven) // [4]
numbers.map(double) // [6, 2, 8, 2, 10, 18]
numbers.sort(compare) // [1, 1, 3, 4, 5, 9]

构造函数类型#

// 构造函数类型使用 new
type Constructor<T> = new (...args: any[]) => T
class User {
constructor(public name: string) {}
}
function createInstance<T>(ctor: Constructor<T>, ...args: any[]): T {
return new ctor(...args)
}
const user = createInstance(User, '张三')
console.log(user.name) // "张三"

抽象构造函数#

// 可以实例化的构造函数
type Constructable<T> = new (...args: any[]) => T
// 抽象构造函数(不能直接实例化)
type AbstractConstructable<T> = abstract new (...args: any[]) => T
abstract class Animal {
abstract speak(): void
}
class Dog extends Animal {
speak() {
console.log('Woof!')
}
}
// 接受抽象类作为参数
function makeAnimal(ctor: AbstractConstructable<Animal>) {
// 不能直接 new,但可以用于类型约束
}

泛型函数预览#

函数可以使用泛型来保持类型关系:

// 泛型函数
function identity<T>(value: T): T {
return value
}
identity<string>('hello') // string
identity<number>(42) // number
identity('hello') // 自动推断为 string
// 泛型箭头函数
const getFirst = <T>(arr: T[]): T | undefined => arr[0]
getFirst([1, 2, 3]) // number | undefined
getFirst(['a', 'b']) // string | undefined

常见问题#

🙋 函数类型的参数名重要吗?#

参数名只用于文档目的,不影响类型兼容性:

type Fn1 = (x: number) => number
type Fn2 = (y: number) => number
// Fn1 和 Fn2 是相同的类型
const fn: Fn1 = (num) => num * 2

🙋 void 和 undefined 返回值有什么区别?#

// void:函数不返回有意义的值
function logVoid(): void {
console.log('log')
// 可以不写 return
}
// undefined:必须显式返回 undefined
function logUndefined(): undefined {
console.log('log')
return undefined // 必须有这行
}
// void 允许返回任何值(用于回调)
type VoidFunc = () => void
const fn: VoidFunc = () => 123 // ✅ 允许

🙋 什么时候用重载,什么时候用联合类型?#

// 如果返回类型与参数类型无关,用联合类型
function process(x: string | number): string | number {
return typeof x === 'string' ? x.toUpperCase() : x * 2
}
// 如果返回类型取决于参数类型,用重载
function process2(x: string): string
function process2(x: number): number
function process2(x: string | number): string | number {
return typeof x === 'string' ? x.toUpperCase() : x * 2
}
// 重载版本有更精确的类型
const s = process2('hello') // string(不是 string | number)
const n = process2(42) // number(不是 string | number)

总结#

特性语法用途
参数类型(a: number)限定参数类型
返回值类型(): number限定返回值类型
可选参数(a?: number)参数可以不传
默认参数(a = 10)参数有默认值
剩余参数(...args: number[])收集多余参数
函数类型type Fn = (x: number) => number定义函数签名
函数重载多个签名 + 实现多种调用方式

下一篇我们将深入学习类型推断与类型断言,掌握 TypeScript 的类型推导机制。