Lets suppose we have function with parameters:
function do(classId: number, schoolId: number, pupilId: number, teacherId: number, roomId: number) {
}
I need to call this function passing object with properties that should fill corresponding function's parameters like:
Case one:
let obj1 = {classId: 1, roomId: 3};
do(obj1); // passed only classId, roomId
Case two:
let obj2 = {schoolId: 5, pupilId: 4};
do(obj2); // passed only schoolId, pupilId
Lets suppose we have function with parameters:
function do(classId: number, schoolId: number, pupilId: number, teacherId: number, roomId: number) {
}
I need to call this function passing object with properties that should fill corresponding function's parameters like:
Case one:
let obj1 = {classId: 1, roomId: 3};
do(obj1); // passed only classId, roomId
Case two:
let obj2 = {schoolId: 5, pupilId: 4};
do(obj2); // passed only schoolId, pupilId
Share
Improve this question
edited Nov 30, 2018 at 14:39
Murat Karagöz
37.7k16 gold badges81 silver badges112 bronze badges
asked Nov 30, 2018 at 14:30
POVPOV
12k40 gold badges128 silver badges229 bronze badges
9
- 2 Take an object as parameter I guess, or am I overseeing something? – Marv Commented Nov 30, 2018 at 14:34
- The problem is that object keys don't have a determined order. In most cases they probably list in the same order they appear on your screen, but that's not a guarantee. – Aaron Beall Commented Nov 30, 2018 at 14:35
- 2 The order does not matter, just go for an object with optional properties and then evaluate which ones are set in the function. There is no reason to have an order – Marv Commented Nov 30, 2018 at 14:39
- Sure, I can pass any set of properties – POV Commented Nov 30, 2018 at 14:39
-
Are you asking: how can I make the specific
do()
function accept an object instead of a list of parameters? Or are you asking: how can I make the specificdo()
function accept either an object or a list of parameters? Or are you asking: given a function which accepts a list of parameters, how can I transform it generically to a different function which accepts an object? – jcalz Commented Nov 30, 2018 at 14:44
3 Answers
Reset to default 6If I got you correctly, you want this:
const Do: (
arg: {
classId?: number;
schoolId?: number;
pupilId?: number;
teacherId?: number;
roomId?: number;
}
) => any = ({ classId, schoolId, pupilId, teacherId, roomId }) => {};
I replaced the list of parameters to a single parameter, that is an object destructuring pattern.
Note, that you cannot use do
as an identifier name, so I changed it to Do
.
Also classic JS functions are not very friendly with types and typescript, so I rewrote it using an arrow function.
The playground
The better approach
First, refactoring the function to take a single object param as in Nurbol's answer (which I upvoted) is IMO the better solution. Long argument lists of numbers are generally hard to use and prone to error.
The literal answer
That said, if you really want to convert an object key's to an argument list for an existing function (for example say do()
is beyond your control and cannot be refactored) like your question states you do have some options.
A naive approach would be to use Object.values()
, which will convert an object's values to an array which can be spread in as function arguments:
do(...Object.values(obj));
However the order of the values is not guaranteed (the same applies to all object key enumerations, like for..in
or forEach()
), so this isn't a good idea if the order of your function arguments matter, which it clearly does in your case.
To guarantee the correct param order you need to explicitly define the order of keys somehow. Here is an example of a generic function which takes an object and array of keys in order, then uses array.reduce()
to produce the ordered argument list array:
function orderedArgs(obj: object, orderedKeys: string[]): any[] {
return orderedKeys.reduce((args, key) => {
args[orderedKeys.indexOf(key)] = obj[key as keyof object];
return args;
}, new Array(orderedKeys.length));
}
const argsOrder = ["classId", "schoolId", "pupilId", "teacherId", "roomId"];
const obj1 = { classId: 1, roomId: 3 };
doFn(...orderedArgs(obj1, argsOrder)); // passes: 1, undefined, undefined, undefined, 3
const obj2 = { schoolId: 5, pupilId: 4 };
doFn(...orderedArgs(obj2, argsOrder)); // passes: undefined, 5, 4, undefined, undefined
You can further abstract this with a helper function:
const callDo = (obj: object) => doFn(...orderedArgs(obj, ["classId", "schoolId", "pupilId", "teacherId", "roomId"]));
callDo({ classId: 1, roomId: 3 }); // passes: 1, undefined, undefined, undefined, 3
callDo({ schoolId: 5, pupilId: 4 }); // passes: undefined, 5, 4, undefined, undefined
Not sure if there any inbuilt functionality for this , but below code could work for you
function doSome(classId,
schoolId,
pupilId,
teacherId,
roomId)
{
console.log(classId,
schoolId,
pupilId,
teacherId,
roomId)
}
const Do = obj => {
var classId , schoolId , pupilId , teacherId , roomId
for(var k in obj){
eval(k + "=" + obj[k])
}
doSome(classId , schoolId , pupilId , teacherId , roomId)
}