Allright, I didn't really come up with anything clever. I may have been to sloppy in the original function/restriction. Obviously once you start passing non-numbers, all bets are off. E.g. a simple add({a: "hello", b: "world"}) breaks. Add may well have been intended as a string concatination function so yeah, fair enough.
A tricky thing I could see without ever explicitly defining "multiplier" (e.g. on the object prototype) is passing a Proxy that e.g. has a fallback for all missing properties. Detecting a proxy is only kind of possible (?) but we can copy all the original target properties from it, which should make it safe.
So here goes, my safe solution for modifying function signature in a non breaking way:
function add({ ...args }) {
const { a, b, ...rest } = args;
if (typeof a !== "number" || typeof b !== "number") {
throw "all arguments must be numbers";
}
if (Object.keys(rest).length > 0) {
throw "You may only pass arguments a and b";
}
return a + b;
}
function _add({ ...args }) {
const { a, b, multiplier = 1, ...rest } = args;
if (
typeof a !== "number" ||
typeof b !== "number" ||
typeof multiplier !== "number"
) {
throw "all arguments must be numbers";
}
if (Object.keys(rest).length > 0) {
throw "You may only pass arguments a, b and multiplier";
}
return a + b * multiplier;
}
Most of these issues (not the proxy one) should be solved by typescript.