Protected instance member inaccessible to same-class constructor via object destructuring assignment
jimmy-zhening-luo opened this issue Β· comments
π Search Terms
class protected member constructor another instance access destructuring assignment same type typescript
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about each common issue, pre-declined request, behavior that looks wrong but is actually right, etc.
β― Playground Link
π» Code
declare const ValidTag: unique symbol;
declare type Tag = string & { [ValidTag]: true };
class User {
public readonly handle: string;
protected _tags: Tag[];
constructor (
user: User,
newTags?: string[],
) {
(
{
handle: this.handle,
_tags: this._tags, // ERROR
} = typeof newTags === "undefined"
? user
: {
handle: user.handle,
_tags: User.checkTags(...newTags),
}
)
this.handle = user.handle;
this._tags = typeof newTags === "undefined"
? user._tags // OK
: User.checkTags(...newTags);
}
private static checkTags(...T: string[]): Tag[] {
return T.filter(
(t: string): t is Tag =>
t.length > 0, // trivial example
);
}
}
π Actual behavior
TypeScript compiler fails to transpile this code to JavaScript, throwing this error on line 15 of the sample code (labeled Case 1
):
Property '_tags' does not exist on type 'User | { handle: string; _tags: Tag[]; }'.
- Type System: This is counterintuitive, because the logic in
Case 2
looks equivalent to the untrained eye (there may be caveats Iβm unaware of), but TypeScript does not error in that case. - Runtime: Although irrelevant to TypeScript desired behavior (as
readonly
is solely a type decoration), ES6 JavaScript equivalent syntax runs as expected:
class Foo {
a; b;
constructor(foo, newB) {
({ a: this.a, b: this.b } = typeof newB === "undefined"
? foo
: { a: foo.a, b: Foo.processB(newB) });
}
static processB(B) { return B }
}
let me = new Foo({ a: 1, b: 2 });
console.log(me); // {a:1, b:2}
console.log(new Foo(me)); // {a:1, b:2}
console.log(new Foo(me, 9001)); // {a:1, b:9001}
π Expected behavior
TypeScript compiler successfully transpiles this code to JavaScript.
Alternative A: TypeScript compiler provides a friendlier error message to help the user fail soft (which can also potentially be Quick Fixed by VSCode).
Alternative B: Wonβt Fix as expected behavior, wherein the closed bug may serve as a handy reference for any future searchers on this topic.
Additional information about the issue
No response
Essentially duplicate of #9974.
What theβ¦ I am bad at searching. π I will confirm in my example and then close as dupe.
I am expecting to see the following behavior if I declare a two interfaces A, B
that mimic class User
β A
with protected _tags
, and B
undecorated or with public _tags
:
new User()
expectsA | User
: βnew User()
expectsB | User
: β
Does that sound right?
EDIT: Never mind. I think thatβs nonsensical on my part; if I understand the original bug correctly, the problem would be that the (undecorated) destructuring assignment call is implicitly public, therefore inherently unable to destructure a type with the same properties at a different privacy level, correct?