Why I use object params
Remember that time you were working on a shared codebase and came across a function you’d not seen before:
await updateUserProfile(
  "user_1234",
  "John Smith",
  false,
  false,
  "[email protected]",
  req.file,
  "admin_007",
  "192.168.0.22"
);
You need to notify the user when their profile is updated. Which argument should you change? Is it even possible to tell from reading this that this is the correct function to modify?
Imagine refactoring this to use a single object argument instead, resulting in clearer and safer code.
await updateUserProfile({
  userId: "user_1234",
  displayName: "John Smith",
  removeAvatar: false,
  notifyUser: false,
  email: "[email protected]",
  avatarFile: req.file,
  auditMetadata: {
    updatedBy: "admin_007",
    ip: "192.168.0.22",
  },
});
Unlike the first function, it’s not possible to mix up the arguments. In fact, you could change their order here with no consequences, giving you a resilience against bugs. No more setting removeAvatar when you intended to set notifyUser!
Likewise, you can now tell clearly what each argument is for and therefore which you need to change. These args are now self-documenting, which is great for ease of maintenance and knowledge transfer in your team.
You can also make any arguments optional, whereas in the first approach optional arguments cannot be followed by non-optional arguments.
Object arguments are my default go-to when making a new function. Sometimes however I prefer plain old arguments, usually when there is a definite and small number of them and it reads clearly.
createDistance(50, 'miles');
Next time you make a function with more than a few arguments, try out a single object argument instead.