I want the qualified type for the functions that are being given as parameters. This type I expect either to be a function with no parameters that returns a void function (Action) that does includes parameters or the void function it returns itself.
Here's the code I want to use:
interface JsonArray extends Array<string | number | boolean | Date | Json | JsonArray> { }
interface Json {
[x: string]: string | number | boolean | Date | Json | JsonArray;
}
type Action = (arg1: string, arg2: Json | JsonArray) => void;
type ReturningAction = () => Action;
function required(arg1: string, ...validationFunctions: Array<ReturningAction | Action>) {
console.log("Test");
}
function oneOf(arg1: string): (arg1: string, arg2: Json | JsonArray) => void {
return (arg1: string, arg2: Json | JsonArray) => {
console.log("Testing");
}
}
function notEmpty(): (arg1: string, arg2: Json | JsonArray) => void {
return (arg1: string, arg2: Json | JsonArray) => {
console.log("Empty");
}
}
required("field", oneOf); // Shouldn't be accepted
required("field", oneOf("test")) // Should be accepted
required("field", notEmpty); // Should be accepted
However it seems, TypeScript ignores extra parameters within the function definition than it expects. Can this be solved?
Even when I do the following:
function required(arg1: string, ...validationFunctions: Array<(arg1: string, arg2: Json | JsonArray) => void>) {
console.log("Test");
}
required("field", oneOf); // Shouldn't be accepted
required("field", oneOf("test")) // Should be accepted
required("field", notEmpty); // Shouldn't be accepted
required("field", notEmpty()); // Should be accepted
All get accepted for some reason, however only the called functions apply.
As I think you noted, TypeScript allows you to pass a function of fewer parameters (e.g., oneOf() takes one parameter) to something that expects a function of more parameters (in this case, validationFunctions[0] should take two parameters, assuming it's an Action). That's because a function is always free to ignore extra parameters passed in, and causing an error there would lead to annoying errors elsewhere (as the linked section of the TypeScript FAQ explains).
EDIT: The following assumes you're using the strictNullChecks compiler option.
One workaround is to declare your oneOf and notEmpty functions so that they work as normal but fail to be interpreted as Action values:
function oneOf(arg1: string, nope?: never): (arg1: string, arg2: Json | JsonArray) => void {...}
function notEmpty(nope?: never): (arg1: string, arg2: Json | JsonArray) => void {...}
Notice the addition of the nope parameter in each case. Now you should get errors where you expect them. Since nope is an optional parameter, you can leave it out, and since it's of type never, you pretty much have to leave it out. So it doesn't really change the way the functions can be used.
There are other fixes but they are heavier-weight... for example, you can make Action and ReturningAction a non-function type which contains the function you want to call.
Hope that helps.
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