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

Uint8Array.prototype.constructor is missing/incorrect type, and probably much more #58796

Closed
BlackAsLight opened this issue Jun 7, 2024 · 8 comments
Labels
Duplicate An existing issue was already created

Comments

@BlackAsLight
Copy link

⚙ Compilation target

esnext

⚙ Library

esnext

Missing / Incorrect Definition

The Uint8Array.prototype.constructor is missing. It doesn't display it in intelisense, but also doesn't complain when you completely type it out. When typed out it has the incorrect type of Function instead of Uint8ArrayConstructor.

Since Uint8Array.prototype.BYTES_PER_ELEMENT exists, it makes sense for the constructor property to as well. I imagine many types are like this, and not just Uint8Array.

Sample Code

const array1 = new Uint8Array(0)
const array2 = new array1.constructor(5)

Documentation Link

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array#instance_properties

@MartinJohns
Copy link
Contributor

MartinJohns commented Jun 7, 2024

Duplicate of #32452 / #3841.

@fatcerberus
Copy link

This bit from #32452 seems worth quoting:

Currently, the type of the constructor property on most objects is Function. It has been suggested that for any class C {}, the type of the constructor property on the instance should be typeof C. However this suffers a significant drawback in that it severely limits subclasses as any subclass of C must have the same (or compatible) construct signatures as C.

@BlackAsLight
Copy link
Author

#32452 is about only accessing the static methods on the constructor and specifically excluding creating another instance of it which is my use case.

Since constructor doesn't have the correct typings on classes, I can't use typescript to validate generic types being passed in based on their constructor's signature without asking for the constructor type to be explicitly provided.

@fatcerberus
Copy link

#32452 is about only accessing the static methods on the constructor and specifically excluding creating another instance of it which is my use case.

Yeah, that requires .constructor to be typed as typeof Class, which runs into the problem laid out in the bit I quoted. Subclass constructors don't have to be substitutable for the base class constructor (not unique to TypeScript - this is true in pretty much all OO languages that I know of), but the proposed behavior would force them to be.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jun 7, 2024
@BlackAsLight
Copy link
Author

Yeah, that requires .constructor to be typed as typeof Class, which runs into the problem laid out in the bit I quoted. Subclass constructors don't have to be substitutable for the base class constructor (not unique to TypeScript - this is true in pretty much all OO languages that I know of), but the proposed behavior would force them to be.

I did play with their playground links and the problem really is that you can't override the constructor signature. Which in my opinion is a flaw in the language to accurately depict the state of the program.

@fatcerberus
Copy link

fatcerberus commented Jun 7, 2024

Concretely, it's possible and common to write code like

class Animal {
    constructor(name: string) {}
}

class Dog extends Animal {
    constructor(name: string, master: Person) {
        super(name);
    }
}

/* ... */

const a: Animal = new Dog("Fido", bob);

which becomes a type error if a.constructor is typed correctly because you can't safely call a.constructor with only one parameter.

@RyanCavanaugh
Copy link
Member

The above example probably deserves one more line of code

class Animal {
    constructor(name: string) {}
}

class Dog extends Animal {
    constructor(name: string, master: Person) {
        super(name);
        console.log(master.name);
    }
}

/* ... */

const a: Animal = new Dog("Fido", bob);
const b = new a.constructor("Hello");

This call will crash, so the program should have an error, but there's no obvious place to put the error -- Dog extends Animal is an idiomatic subclassing; a: Animal = new Dog() is an idiomatic subtyping, and a.constructor("Hello") is the thing the issue proposes should be legal.

@BlackAsLight
Copy link
Author

I see what you mean, that is unfortunate :(

@BlackAsLight BlackAsLight closed this as not planned Won't fix, can't repro, duplicate, stale Jun 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants