在将JavaScript库协议转换为TypeScript时,我偶然发现了使用前导可选参数,而不是常规/尾随。
JavaScript中的方法:
db.task(function (context) {
// executing task
});
有一个可以在前面注入的任务的可选名称:
db.task('myTaskName', function (context) {
// executing task
});
这样做是为了使代码更具可读性,将任务名称放在前面,而不是最后的某个地方,这看起来是错误的/不直观的。
如何在TypeScript中围绕这些参数进行编码?
我知道我可以将这两个参数声明为可选参数,但事实并非如此,因为回调函数需要作为第一个或第二个参数。如果它使这更简单,我们可以说 - 最后一个参数必须是回调函数。
答案 0 :(得分:7)
接受的答案使用了一些hacky:
myDefinedMethod('test')
,即不提供回调)。相反,应该使用函数重载:https://basarat.gitbooks.io/typescript/content/docs/types/functions.html 以下是一个例子:
type Cb = (context: any) => any;
function task(cb: Cb);
function task(name: string, cb: Cb);
function task(nameOrCb: string | Cb, cb?: Cb) {
if (typeof nameOrCb === 'string') {
const name = nameOrCb; // You can see that `name` has the inferred type `string`
// do something
}
else {
const cb = nameOrCb; // You can see that `cb` has inferred type `Cb`
// do something
}
}
// Tests
task((a) => null); // Ok
task('test', (a) => null) // Ok
// Type Safety
task((a, b) => null); // Error: function does not match type cb
task('test'); // Error: `cb` must be provided for this overload
答案 1 :(得分:3)
如果您的意思是在函数中定义参数,则应使用?
符号标记它们,并使用|
显示可以注入的各种类型。在函数本身中,您必须查看传递给哪个函数的内容。 RequireJS
在其定义函数中执行此操作,并且它们具有显示此内容的.d.ts
(明确键入的)文件。
方法/功能的示例
// definition
function myDefinedMethod(callback: (someVar:any)=>any):void;
function myDefinedMethod(name: string, callBack: (someVar: any) => any): void;
function myDefinedMethod(nameOrCallback: string | ((someVar:any)=>any), callBack ?: (someVar: any) => any): void {
var name = "";
if (typeof nameOrCallback === 'string') {
name = nameOrCallback;
}
else {
callBack = nameOrCallback;
}
// both name and callback are now defined although name can be empty
// do something
console.log(name);
}
nameOrCallback
可以是参数的函数或名称。如果是字符串,则callback
无法定义。 谢谢@basarat ,我已根据您的反馈更新了我的回答。这确实是一个更好的结构,因为您确保调用者无法在不提供预期的强制参数(如回调)的情况下执行您的方法。之前我确实使用过Function
,但仅作为OP想要使用的任何函数定义的占位符,并且不打算作为最终类型参数。为了澄清这一点,我使用像你这样的内联回调定义更新了代码。
再次感谢您的意见。这确实通过确保类型安全性并确保调用者只能按预期调用方法来使代码更好。