Hacker News new | ask | show | jobs
by dragonwriter 1088 days ago
Its a footgun that results from JS’s loose typing of functions, allowing them both to be called with discarded arguments and to be flexible in the number of arguments they accept.

While each of those flexibilities can be useful, they interact in annoying ways. The fact that map passes three arguments but is often used as if it was passing one, and that parseInt accepts two arguments but is often used as if it accepted one makes it very easy to make this mistake.

1 comments

> Its a footgun that results from JS’s loose typing of functions, allowing them both to be called with discarded arguments and to be flexible in the number of arguments they accept.

This just goes to show how one can use a language without actually understanding its core semantics. Additional arguments aren't "discarded" at all: they're still available to the called function in via `arguments`, they're just not required to be assigned a name in the function signature.

Basically, a Javascript function fn() declaration is equivalent to Python's def fn(*args): declaration and you have the option to assign a name to positional arguments. Any named positional argument that is not provided by the caller simply leaves the argument uninitialized, i.e. undefined.

It's a core concept of the language and I'm always puzzled when non-beginners struggle with this. That's also a very good reason to not use vanilla Javascript at all and skip straight to TypeScript and its brethren instead.

TypeScript has the same problem.
It helps avoiding number of arguments problems, though. Of course it doesn't change the core semantics of JS.
> It helps avoiding number of arguments problems, though

This issue is all about the number of arguments problem, and TypeScript (in cases like this) won't flag that problem. Which is something I think it should.

If you manually unroll the "map" and call parseInt() explicitly with the same arguments that map() calls parseInt() with, TypeScript will flag that. But not when map() is in the picture.

I understand why they chose to do that, but I still disagree with it.

he he I tried to fix this in Typescript but look like they do not care So I made and use (for my projects) my own version of typescript ;-) https://www.npmjs.com/package/@topce/typescript/v/5.1.6 There indeed you would have compile time error

error TS2345: Argument of type '(string: string, radix?: number) => number' is not assignable to parameter of type '(value: string, index: number, array: string[]) => number'. Target signature provides too few arguments. Expected 3 , but got 2.

console.log(["1","2","3"].map(parseInt));

This is great - I will definitely check this out.

I'm curious - have you been using this for long? Have you noticed any code which this flagged and which you thought it was being too strict? I feel like I would want this flag on all of the time, but I'm curious if there are edge cases that I have not considered but maybe you have experienced.