Curry
You can change your function, so instead of taking two argument, it takes one, then returns a second function that takes the second argument. This is known technique is known as curry.
// maxLengthValidator :: number -> string -> boolean
const maxLengthValidator = (boundary: number) => (val: string) : boolean => {
if (val.length > boundary) return false;
return true;
};
// ... later ...
validator: maxLengthValidator(255);
This way you can create different validators by invoking the function: maxLengthValidator(10)
will give you a validator for 10 characters you can use. Since it's a function, you can just assign it to a variable, too:
//userNameLengthValidator :: string -> boolean
const userNameLengthValidator: (val: string) => boolean = maxLengthValidator(10);
Swap parameters to accommodate partial allocation
Instead of taking value then max length, take the length first. Same thing that currying the function did but instead this one can still take two parameters:
const maxLengthValidator = (boundary: number, val: string): boolean => {
if (val.length > boundary) return false;
return true;
};
// ... later ...
validator: maxLengthValidator.bind(this, 255);
Same basic idea. This time you have a bit more flexibility, though - you can call the function with both parameters maxLengthValidator(10, username)
or just partially apply it with one. The latter produces pretty much the same thing as currying, since you still get a new function with the same signature:
//userNameLengthValidator :: string -> boolean
const userNameLengthValidator: (val: string) => boolean = maxLengthValidator.bind(this, 10);
Despite the similarities currying is not partial application. Also, it's possible to curry a function of any arity (any amount of parameters) to be able to take either one or many at a time. For an example, you can see _.curry
in Lodash
function add4(a, b, c, d) {
console.log(a + b + c + d);
}
const curryAdd4 = _.curry(add4);
curryAdd4(1)(2)(3)(4);
curryAdd4(1, 2, 3, 4);
curryAdd4(1)(2, 3)(4);
curryAdd4(1, 2, 3)(4);
curryAdd4(1)(2, 3, 4);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
Partially apply with a placeholder or from the right
You can leave the signature as is, and just change your partial application. Function#bind
is not very flexible but you can write your own or (better yet) use a library. I'll use Lodash again, since it has a good implementation for these:
Partial application with a placeholder
Allows you to skip some of the parameters when partially applying. So you can skip the first one and just set the second:
const maxLengthValidator = (val, boundary) => {
if (val.length > boundary) return false;
return true;
};
//userNameLengthValidator :: string -> boolean
const usernameLengthValidator = _.partial(maxLengthValidator, _, 10);
console.log(usernameLengthValidator("usernameTooLong"));
console.log(usernameLengthValidator("user"));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
Partially apply from the right
Partially apply starting from right to left, so it will first set boundary
:
const maxLengthValidator = (val, boundary) => {
if (val.length > boundary) return false;
return true;
};
//userNameLengthValidator :: string -> boolean
const usernameLengthValidator = _.partialRight(maxLengthValidator, 10);
console.log(usernameLengthValidator("usernameTooLong"));
console.log(usernameLengthValidator("user"));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>