3

I try to use Uint8Array to simulate a byte[] or uint8[].

TypedArray.subarray creating a new view on the existing buffer,changes to the new object's contents will impact the original object and vice versa.

I always use it like this:

let u = new Uint8Array(8) //'u' is 8 bytes
let a = u.subarray(4) //'a' is 4 bytes
console.log(a) // show [0,0,0,0], it is ok 

but when I try to subclassing Uint8Array, subarray goes strange.

class bytes extends Uint8Array {
  constructor(arg) {
    super(arg)
  }
}

let b = new bytes(8) //'b' is 8 bytes
let c = b.subarray(4) //'c' should be 4 bytes, but is 8 bytes
console.log(c) // show [0,0,0,0,0,0,0,0], ??????

I want to know what happened and how to fix it.

1
  • Interesting... Both on Chromium and Firefox. Commented Feb 19, 2020 at 7:30

2 Answers 2

4

It has to do with how arguments are interpreted by the overloaded constructor.

This works correctly:

class bytes extends Uint8Array {
  constructor(...args) {
    super(...args);
  }
}

let b = new bytes(8);
let c = b.subarray(4);
console.log(c);

Sign up to request clarification or add additional context in comments.

1 Comment

constructor(buffer, byteLength, byteOffset) { super(buffer, byteLength, byteOffset);}//it is ok
0

This bug shows up because Uint8Array.prototype.subarray() creates a new instance calling the Uint8Array(buffer, byteOffset, length) constructor. By inheritance, the child class subarray() method (and maybe others) will call the child class constructor.

Adapting @robby-cornelissen's answer to TypeScript

class bytes extends Uint8Array {
  constructor(...args: any[]) {
    // @ts-expect-error on spread operator
    super(...args);
  }
}

let b = new bytes(8);
let c = b.subarray(4);
console.log(c);

Or if you'd rather not use the @ts-expect-error hack, another way seems to rewrite the overloaded constructors:

class bytes extends Uint8Array {
  constructor(length: number);
  constructor(array: ArrayLike<number>);
  constructor(buffer: ArrayBufferLike, byteOffset?: number, length?: number);
  constructor(
    lengthOrBuffer: number | ArrayLike<number> | ArrayBufferLike,
    byteOffset?: number,
    length?: number
  ) {
    if (typeof lengthOrBuffer === 'number') {
        super(lengthOrBuffer);
    } else if (lengthOrBuffer instanceof ArrayBuffer) {
        super(lengthOrBuffer, byteOffset, length);
    } else {
        super(lengthOrBuffer);
    }
  }
}

let b = new bytes(8);
let c = b.subarray(4);
console.log(c);

2 Comments

…or much simpler, to omit the constructor altogether if all it does is to call super(...args).
Indeed, but in my case I wanted to add some more things in my subclass constructor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.