Repository navigation
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
MartinFerret commentedon Nov 6, 2026
I'd like to work on this.
Before writing the PR, I checked the two possibilities for the extra generic overloads (length,
ArrayLike<number>, the union case andIterable<number>), added toUint8ArrayConstructorthrough declaration merging, in TypeScript 6.0.3 and 7.0.2, against the original examples and theEncodedString extends Uint8Array<ArrayBufferLike>case.Returning
Uint8Array<TArrayBuffer>(as suggested in the issue) solves all of them, including the subclass. However,new Uint8Array<SharedArrayBuffer>(4)would type-check, although the constructor always allocates anArrayBuffer.Returning
Uint8Array<ArrayBuffer>is sound and solves the direct calls ofnew Uint8Array<ArrayBufferLike>(source), but the subclassing case fails with TS2510 ("Base constructors must all have the same return type").In both cases, constructor calls without type arguments keep their current types. For example,
new Uint8Array(10)remainsUint8Array<ArrayBuffer>.Only the first shape solves the subclassing case that motivated the issue. Would you accept this trade-off? If this is OK, I will update all typed array constructors (including the BigInt ones) in the lib files and add compiler tests for explicit type arguments and subclassing, as well as the existing call forms.
trentmillar commentedon Nov 7, 2026
Martin Ferret (@MartinFerret) small heads up if you're putting a PR together β
lib.es2017.typedarrays.d.ts(the 0-argnew ()constructor) andlib.es2025.float16.d.ts(Float16ArrayConstructor) also haveTypedArrayconstructors that'll need the generic overloads sosuper()andFloat16Array<ArrayBufferLike>work too.MartinFerret commentedon Nov 7, 2026
Thanks Trent Millar (@trentmillar), that matches what I saw! I'm definitely putting a PR together.
MartinFerret commentedon Nov 7, 2026
I hadn't seen #65376 when I wrote my last comment, it covers exactly this, so I'll leave it there.