While converting a JavaScript library protocol into TypeScript, I stumbled upon use of leading optional parameters, as opposed to regular / trailing ones.
A method in JavaScript:
db.task(function (context) {
// executing task
});
has an optional name for the task that can be injected in front:
db.task('myTaskName', function (context) {
// executing task
});
This is done to make the code more readable, having the task name up in front, as opposed to somewhere in the end, which would look wrong / unintuitive.
How does one code around such parameters in TypeScript?
I know I can declare both parameters as optional, but this wouldn't be the case, because the callback function is required as either the first or the second parameter. And if it makes this any simpler, we could say - the last parameter must be a callback function.
In Typescript, making optional parameters is done by appending the “?” at the end of the parameter name in the function when declaring the parameters and the parameters which are not marked with “?” i.e not optional parameter are called as default parameters or normal parameters where it is must and compulsory to pass ...
TypeScript provides a Optional parameters feature. By using Optional parameters featuers, we can declare some paramters in the function optional, so that client need not required to pass value to optional parameters.
Developers can use the optional parameter to declare parameters in function optional so that the requirement to pass the value to optional parameters gets eliminated.
You must tell TypeScript if a property is optional. First, if you don't tell TypeScript that a property is optional, it will expect it to be set. Adding ? to the property name on a type, interface, or class definition will mark that property as optional.
The accepted answer uses a few hacky things:
myDefinedMethod('test')
i.e. no callback is provided). Instead one should use function overloading : https://basarat.gitbooks.io/typescript/content/docs/types/functions.html
Here is an example:
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
If you mean when you are defining parameters in your function you would mark them with the ?
symbol for optional and use the |
to show the various types that could be injected. In the function itself you have to see what was passed in to which function. RequireJS
does this in their define functions and they have a .d.ts
(definitely typed) file that shows this.
Example with a method/function
// 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
could be either the function or the name of the parameter. If it is a string then the callback
cannot be undefined.Thank you @basarat, I have updated my answer based on your feedback. This is indeed a better structure as you are ensuring the caller cannot execute your method without supplying the expected mandatory parameters like the callback. I did use Function
before but only as a placeholder for whatever function definition that the OP would want to use and was not intended as a final type parameter. To clarify this I have updated the code with an inline callback definition like yours.
Again, thank you for your input. This does indeed make the code better by ensuring type safety and ensuring that a caller can only call the method as intended.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With