Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Callback with variable number of arguments, is converted into a function with a single argument #354

Open
Booksbaum opened this issue Oct 24, 2020 · 0 comments

Comments

@Booksbaum
Copy link
Contributor

A function with a variable number of arguments, passed as argument to another function, gets converted into a function with just a single argument:

declare function call(f: (...args: number[]) => void): void;

gets converted to

type [<AllowNullLiteral>] IExports =
    abstract call: f: (ResizeArray<float> -> unit) -> unit

I think the idea is for ResizeArray to contain all passed arguments. But it's actually just the first argument:

function call(f: (...args: number[]) => void): void {
    f(3, 5)
}
let [<Global>] call (f: ResizeArray<float> -> unit): unit = jsNative

call (fun args -> printfn "Args=%A" args)

(Fable repl)

Output:

args=3

Even worse: What is ResizeArray<float> in F#, is actually float during runtime -- which means functions of ResizeArray will fail at runtime or produce unexpected results:

call (fun args -> printfn "Length=%i" args.Count)
// Length=0
call (fun args -> for arg in args do printfn "* %f" arg)
// Uncaught TypeError: xs[Symbol.iterator] is not a function

(Fable repl)

Especially confusing when args is a type compatible to array during runtime like string:

function call(f: (...args: string[]) => void): void {
    f("Alpha", "Beta")
}
let [<Global>] call (f: ResizeArray<string> -> unit): unit = jsNative

call (fun args -> printfn "args=%A" args)
call (fun args -> printfn "Length=%i" args.Count)
call (fun args -> for arg in args do printfn "* %s" arg)

(Fable repl)

Output:

args=Alpha
Length=5
* A
* l
* p
* h
* a

-> only first argument -> iterating over characters of first string

Probably even more confusing with ...args: any[] instead of a fixed type.




I'm not sure what the correct code would be.

... in TS/JS is [<ParamArray>] in F# -- but Attributes aren't allowed here.
Currently the best option is probably to create an overload for each expected call by hand. But for that one must know with how many arguments the function gets called. (And it isn't auto-generated)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant