Skip to content

Instantly share code, notes, and snippets.

@MKRhere
Last active February 18, 2020 11:57
Show Gist options
  • Save MKRhere/f8e1a96e2bc53c6ffbad8c23f44b88af to your computer and use it in GitHub Desktop.
Save MKRhere/f8e1a96e2bc53c6ffbad8c23f44b88af to your computer and use it in GitHub Desktop.
Extend Array with Proxies for fancy features
const betterArray = xs => new Proxy(xs, {
get (xs, key) {
if (xs[key] || !xs.length) return xs[key];
const idx = Number(key);
if (!idx || idx > 0) return xs[key];
return xs[xs.length + idx];
},
});
const arr = betterArray([ 1, 2, 3, 4, 5 ]);
arr[-1]; // 5
arr[-2]; // 4
const isNumber = x => typeof x === "number";
const isFunc = x => typeof x === "function";
const makeArrayCallable = xs => (...args) => {
switch (args.length) {
case 0: return callableArray([...xs]);
case 1: {
const [arg] = args;
switch (typeof arg) {
case "number": {
if (arg >= 0) return xs[arg];
else return xs[xs.length + arg];
}
case "function":
return callableArray(xs.map(arg));
default:
throw new TypeError("Invalid call signature: " + typeof arg);
}
}
case 2: {
if (args.every(isNumber)) return callableArray(xs.slice(...args));
const [arg1, arg2] = args;
if (isFunc(arg1)) return callableArray(xs.reduce(arg1, arg2));
else throw new TypeError(`Invalid call signature: ${typeof arg1} ${typeof arg2}`);
}
}
}
const callableArray = xs => new Proxy(makeArrayCallable(xs), { get (_, key) { return xs[key] } });
const arr = callableArray([ 1, 2, 3, 4, 5 ]);
arr(3); // 4
arr(1, 3); // Callable<[ 2, 3, 4 ]>
arr(x => x + 1); // Callable<[ 2, 3, 4, 5, 6 ]>;
arr((a, b) => a + b, 0); // 15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment