-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Unable to assign Symbol.toStringTag to a class inheriting from Uint8Array #50923
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
Comments
This is what you're trying to do: class Base { get val(): 'base' { return 'base' } }
class Derived extends Base { get val() { return 'derived' } } |
Then Uint8Arrays definitions are wrong, no? You can do this and it works in JS. It seems this objects definitions are overly strict / incorrect is the problem. |
It's a consequence of TypeScripts structural typing. Without this specific return type, the different typed arrays would be structurally compatible, and allow you to assign them to one another. See #48617. I don't know your code base, but I'd generally favor composition over inheritance. |
@MartinJohns That issue shows that they are structurally the same. It looks like this has changed since then, as the example in that issue no longer succeeds. As that issue is marked as |
It shows that they are structurally the same, unless you import |
Oh I see, then this is not a regression but an existing bug. Nevertheless the problem seems to be that the definitions for these types are incorrect. |
It's neither a regression, nor a bug. It's intentional, to prevent these types from being structurally compatible. Without this explicit return type (provided in the lib "ES2015.Symbol.WellKnown"), you could assign a |
I don't agree, correct types that reflect reality are more important than working around limitations of the type system. Since these types are structurally identical they should be treated as such. The way to fix this problem is to add features; such as a compile-time only branding mechanism so you can make the objects structurally different without having that reflect on run-time code. Regardless, the type definitions should reflect what these properties actually return. |
You canβt please everyone: #31311 In both cases the types donβt reflect reality in some respect, but TS has to make a decision and the options here are mutually exclusive. |
Yeah to be clear I'm not proposing a feature in this issue. This issue would not be fixed by such a feature. This feature is fixed by updating the types to return a string, as that's how it is specced. |
If they update the return type as proposed, they can also open #48617 again (which is working as intended and would break by your suggestion). Hence why fatcerberus said you can't please everyone. Being 100 % spec compliant is not a goal of TypeScript, as per their language Design Goals. Instead they aim for a compromise between soundness and usability. It's unfortunate that TypeScript does not support nominal types for cases like this, but that's how it is for now. |
To be clear, this is a bug and #48617 is a feature request. Normally you wouldn't create a bug in order to work-around the lack of a feature. That's why it's not clear to me that this bug is intentional, as you are suggesting. In any event, I wonder if this can be fixed by adding a type-param? That way the normal non-extended case would continue to work as desired, but if you needed to extend you could provide a type param for the toStringTag return. Something like: class Bytes extends Uint8Array<'Bytes'> {
get [Symbol.toStringTag]() {
return 'Bytes';
}
} Or perhaps another interface to keep the regular Uint8Array use-case cleaner? class Bytes extends ExtendedableTypedArray<Uint8Array, 'Bytes'> {
get [Symbol.toStringTag]() {
return 'Bytes';
}
} |
That actually happens often with TS due to various design constraints and is why the
Note "equally-correct" doesn't imply the options are 100% correct, just that they have about the same "correctness value". Both options available today are wrong in some way:
I would go so far as to argue that point 2 is a minor inconvenience in most cases (you can always add a |
ts-ignore doesn't carry over into declaration files. Curious your thoughts on the type param idea. |
I'm not a TS team member, but I doubt very much they'd want to add a type parameter and make the types generic just to specify the value of |
This is the intended behavior; subclassing is subtyping and a class that returns a different value for I would recommend writing class Bytes extends Uint8Array {
get [Symbol.toStringTag]() {
return 'Bytes' as any;
}
} if you intend to make a new class with a subtyping violation (no judgment π ). If you're trying to get the |
Thank you for your time. |
The fact that the libs define Perhaps there should be a way to declare "phantom" properties that can be referenced by types, but any runtime code that tries to access such properties is a compile error. |
Bug Report
π Search Terms
symbol.toStringTag, uint8array
π Version & Regression Information
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
As far as I'm aware you can add
Symbol.toStringTag
to any object.π Expected behavior
No error
The text was updated successfully, but these errors were encountered: