Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Math.min.apply on a Float32Array

Tags:

typescript

I ran into the following issue with a similar example to the code below while converting a JS file into TS:

let arr = Float32Array(3)
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
    
let min_value = Math.min.apply(null, arr);

In this example, TypeScript would produce an error with the following message:

Argument of type 'Float32Array' is not assignable to parameter of type 'number[]'.
  Type 'Float32Array' is missing the following properties from type 'number[]': pop, push, concat, shift, and 5 more.

Imagining that arr is performance sensitive variable which should not be converted to number[], the most obvious solution to trick the compiler into working would be casting the variable instead:

let min_value = Math.min.apply(null, arr as unknown as number[]);

Is there a specific reason / danger as to why apply should not be able to receive a Float32Array parameter in this case?

like image 587
Francisco Teotónio Avatar asked Sep 12 '25 13:09

Francisco Teotónio


1 Answers

Function.prototype.apply() states that the arguments parameter can be any array-like object.

Typed Arrays are array-like objects, so they should be accepted by the apply method.

Furthermore, the Math.min specification states that its arguments do not even need to be numbers:

Given zero or more arguments, this function calls ToNumber on each of the arguments and returns the smallest of the resulting values.

Knowing all of the above, what you are trying to do looks correct and it seems like a TypeScript bug.

As for why that is happening, currently the definitions for Math.min and CallableFunction.apply are as follows:

min(...values: number[]): number;

apply<T, A extends any[], R>(
  this: (this: T, ...args: A) => R,
  thisArg: T,
  args: A
): R;

Most likely both these definitions need to be adapted to act according to the standards.

EDIT: Likely only the apply definition needs to be changed to something like:

apply<T, A extends Iterable<AT>, AT, R>(
  this: (this: T, ...args: AT[]) => R,
  thisArg: T,
  args: A
): R;

Or to be more correct, ArrayLike<AT> should be used instead of Iterable<AT>, but for the above to work ArrayLike would need to extend from Iterable

like image 134
Jorge Galvão Avatar answered Sep 14 '25 05:09

Jorge Galvão