函数是 JavaScript 和 TypeScript 中最基本的代码组织单元。TypeScript 为函数添加了类型系统,让函数的参数和返回值都有明确的类型约束,提高了代码的安全性和可读性。
TypeScript 支持多种函数定义方式,每种方式都可以添加类型注解。
function add(a: number, b: number): number {
return a + b
}
const subtract = function(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
console.log(add(10, 5))
console.log(subtract(10, 5))
console.log(multiply(10, 5))
console.log(divide(10, 5))
四种写法各有特点:函数声明会提升,函数表达式更灵活,箭头函数适合简短逻辑。
函数参数可以指定类型,调用时 TypeScript 会检查参数类型是否匹配。
function greet(name: string, age: number): string {
return `你好,我是 ${name},今年 ${age} 岁`
}
console.log(greet("张三", 25))
如果传入错误类型的参数,编译时会报错。这避免了运行时的类型错误。
函数可以指定返回值类型,TypeScript 会检查返回值是否符合声明的类型。
function isAdult(age: number): boolean {
return age >= 18
}
function getAge(birthYear: number): number {
return new Date().getFullYear() - birthYear
}
console.log(isAdult(20))
console.log(getAge(1990))
返回值类型可以省略,TypeScript 会自动推断。但显式声明返回值类型可以让代码意图更清晰。
可以用类型表达式描述函数的类型,常用于定义回调函数的类型。
type MathOperation = (a: number, b: number) => number
const calculate = (op: MathOperation, a: number, b: number): number => {
return op(a, b)
}
const add: MathOperation = (a, b) => a + b
const subtract: MathOperation = (a, b) => a - b
console.log(calculate(add, 10, 5))
console.log(calculate(subtract, 10, 5))
MathOperation 定义了一个函数类型,接受两个数字参数,返回一个数字。
函数类型也可以用调用签名的形式定义,这种写法更接近接口的定义方式。
interface Calculator {
(a: number, b: number): number
}
const add: Calculator = (a, b) => a + b
console.log(add(10, 5))
调用签名常用于描述可以调用的对象,特别是那些既有属性又能调用的函数。
不返回值的函数使用 void 类型。
function log(message: string): void {
console.log(`[LOG] ${message}`)
}
function forEach<T>(arr: T[], callback: (item: T) => void): void {
for (const item of arr) {
callback(item)
}
}
log("应用启动")
forEach([1, 2, 3], (n) => console.log(n * 2))
void 表示函数没有返回值,或者返回值不重要。
永不返回的函数使用 never 类型,比如抛出异常或无限循环的函数。
function throwError(message: string): never {
throw new Error(message)
}
function infiniteLoop(): never {
while (true) {}
}
function fail(message: string): never {
return throwError(message)
}
never 表示函数永远不会正常结束,这在类型推断中很有用。
函数重载允许一个函数有多种调用签名,根据参数类型执行不同的逻辑。
function format(input: string): string
function format(input: number): string
function format(input: string | number): string {
if (typeof input === "string") {
return `字符串: ${input}`
}
return `数字: ${input}`
}
console.log(format("hello"))
console.log(format(123))
重载签名描述了函数的不同调用方式,实现签名包含实际的逻辑代码。
函数类型在实际开发中有很多应用场景。比如定义事件处理器的类型:
type EventHandler = (event: Event) => void
interface EventEmitter {
on(event: string, handler: EventHandler): void
emit(event: string, data?: any): void
}
class SimpleEmitter implements EventEmitter {
private handlers: Map<string, EventHandler[]> = new Map()
on(event: string, handler: EventHandler): void {
const handlers = this.handlers.get(event) || []
handlers.push(handler)
this.handlers.set(event, handlers)
}
emit(event: string, data?: any): void {
const handlers = this.handlers.get(event) || []
handlers.forEach(handler => handler(data))
}
}
const emitter = new SimpleEmitter()
emitter.on("message", (e) => console.log("收到消息:", e))
emitter.emit("message", "你好")
TypeScript 的函数类型系统让函数的定义更加严谨。通过参数类型和返回值类型,可以在编译时发现类型错误。函数类型表达式和调用签名提供了灵活的类型定义方式。掌握函数类型是编写类型安全代码的基础。