voraa, я это себе как-то так представляю(чисто черновой набросок):
function create ({tag, options, children, parent}) {
console.log({tag, options, children, parent})
}
function isType(arg, types) {
if(Array.isArray(types))
return types.some(type => isType(arg, type));
if(typeof types === 'function')
return types(arg);
return arg === types;
}
function findArgs(args, list) {
let maxArgsMatchLength = -1;
let maxArgsMatchNames;
list.forEach(({
sublist,
sublist: { length },
names
}) => {
if(length <= maxArgsMatchLength) return; // ничего не делаем если уже нашли больше аргументов
for(let i = length; i--;) {
if(!isType(args[i], sublist[i]))
return false;
}
maxArgsMatchLength = length;
maxArgsMatchNames = names;
});
if(maxArgsMatchLength === -1)
throw new Error('invalid arguments');
return Object.fromEntries(
maxArgsMatchNames
.slice(0, maxArgsMatchLength)
.map((key, i) => [key, args[i]])
)
}
function withAttrs(func, list) {
const bigList = list.flatMap(obj => {
const sublist = [];
const entries = Object.entries(obj);
const current = [];
const names = [];
for(let arg in obj) {
const type = obj[arg];
if(arg.endsWith('?')) {
arg = arg.slice(0, -1);
sublist.push(current.slice());
}
names.push(arg);
current.push(type)
}
sublist.push(current);
return sublist.map(arr => ({ sublist: arr, names }));
})
return function(...args) {
return func.call(this, findArgs(args, bigList));
}
}
isNode = () => true;
createWithArgs = withAttrs(create, [
{tag: isString, options: isPlainObject, 'children?': [isNode, isArray, isString], 'parent?': isElement},
{tag: isString, 'children?': [isNode, isArray, isString, null], 'parent?': isElement},
]);
createWithArgs('1', {a: 3}, [])
Все isX функции из lodash, но естественно возможно использование своих.
+Обязательно должно бы кэширование: чтоб одна функция проверки типа вызывалась для одного конкретного аргумента только один раз.
+Разделить проверку списка аргументов не всех сразу, а по порядку.
+Добавить поддержку spread.
+Типизировать для typescript(это будет ад, если вообще возможно).
...
=)