问题背景:
回调函数是 JavaScript 和 TypeScript 中异步编程和委托责任的常见做法。在 TypeScript 中,对这些函数的类型化是确保安全性的重要部分,尤其是当参数可能是可选的或具有默认值时。
问题:
在动态的 JavaScript 中,缺乏对回调参数的类型化会导致值传递错误、与 undefined 混淆以及参数顺序错误。在 TypeScript 中,类型化是避免这类问题的必要步骤,但在外部很难遵循与可选性、顺序和默认值相关的所有细节。
解决方案:
明确指定所有参数的类型,用问号表示可选参数,并在函数声明时直接指定默认值,确保在类型中正确描述它们。
代码示例:
function fetchData( url: string, callback: (data: any, error?: Error) => void ) { // ... } // 带有可选参数 error 的回调 fetchData('/api', (data, error) => { if (error) { // 处理 } else { // 成功 } }); // 带有默认参数的回调 function process( cb: (x: number, y?: number) => void = (x, y = 10) => { /* ... */ } ) { /* ... */ }
关键特点:
回调的消费者是否需要明确考虑所有参数,包括可选参数?
不需要,他们可以省略可选参数,TypeScript 不会报错 — 处理是正确的,因为使用了问号语法。
可以将回调的第一个参数设为可选,第二个参数设为必需吗?
不可以。可选参数必须始终在参数列表的最后。打破这一顺序会导致类型错误。
如果不标明参数的可选性,但又未在调用时传递该参数,会发生什么?
TypeScript 会报错 — 如果参数是必需的,必须传递。只有可选或默认参数可以被省略。
将回调的第二个参数标记为必需,但在调用时未传递。导致编译错误。
优点:
缺点:
对带有可选参数的回调进行类型化:
(cb: (x: number, y?: number) => void)
或指定默认值:
f = (x: number, y = 10) => { ... }
优点:
缺点: