Generic TypedArray constructors have only one overload #61680
Description
🔎 Search Terms
Uint8Array
🕗 Version & Regression Information
- This is the behavior in versions 5.8.3 and 5.7.3
- I was unable to test this on prior versions because
Uint8Arrayis not generic in earlier versions
⏯ Playground Link
💻 Code
const source = new Uint8Array(10);
const copy1 = new Uint8Array(source); // OK
const copy2 = new Uint8Array<ArrayBufferLike>(source); // TS 2345
const copy3 = new Uint8Array<ArrayBuffer>(source); // TS 2345🙁 Actual behavior
Only the generic constructor overload of Uint8Array is available when using Uint8Array with a generic parameter, i.e. the one which accepts a TArrayBuffer as the first argument. It is therefore not possible to pass a Uint8Array as the first argument without a compile error, even though this is valid.
🙂 Expected behavior
It should be possible to use all the valid overloads of Uint8Array (and friends) constructor without a compiler error.
Additional information about the issue
This seems to only affect target value of ES2024 or ESNext, but I can't figure out why from looking at the types.
I assume this behaviour occurs for the same reason as given in this comment. In that case I assume the fix would be adding copies of all the constructor overloads to the Uint8ArrayConstructor interface, but with type parameters.
For example, the following works (TS Playground):
interface Uint8ArrayConstructor {
// this is just a copy of existing overloads, with `TArrayBuffer` param added
new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(
length: number,
): Uint8Array<TArrayBuffer>;
new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(
array: ArrayLike<number>,
): Uint8Array<TArrayBuffer>;
new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(
buffer: ArrayBuffer,
byteOffset?: number,
length?: number,
): Uint8Array<TArrayBuffer>;
new <TArrayBuffer extends ArrayBufferLike = ArrayBuffer>(
array: ArrayLike<number> | ArrayBuffer,
): Uint8Array<TArrayBuffer>;
}
const source = new Uint8Array(10);
const copy1 = new Uint8Array(source);
const copy2 = new Uint8Array<ArrayBufferLike>(source);
const copy3 = new Uint8Array<ArrayBuffer>(source);I think this is basically the opposite problem to that which was fixed by #60934.
Activity
RyanCavanaugh commentedon May 14, 2025
I don't understand what you're trying to do here. In the case where you're passing a
Uint8Array, there's nothing generic to do, so it's not necessary/useful/etc to pass a type argument. What's the actual code you're trying to write where this type argument would be doing something?gordonmleigh commentedon May 19, 2025
It's a derived class, similar to this, which I've still trimmed for brevity (playground):
If I give no type parameters for
Uint8Array, then the secondsupercall has a compiler error. If I give the type parameter forUint8Array, then the firstsupercall has a compiler error. If I makeEncodedStringgeneric overTArrayBufferthen obviously it has the same problem as the latter.Perhaps it is a little odd what I'm trying to do, i.e. subclassing
Uint8Array, but I figure that this problem will affect anything which needs to be generic forTArrayBufferforUint8Arrayand also create an instance. Due to the calling union types caveats, the generic and non-genericUint8Arrayare now effectively two different class types, each with different constructors. That surely wasn't the intention when the generic version was introduced.RyanCavanaugh commentedon Jun 5, 2025
We can try a PR and this seems OK as long as it doesn't break something else