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

Accessing protected properties with this argument specifier differs with interface #29132

Open
MasGaNo opened this issue Dec 23, 2018 · 2 comments
Labels
Bug A bug in TypeScript
Milestone

Comments

@MasGaNo
Copy link

MasGaNo commented Dec 23, 2018

TypeScript Version: 3.2.2

Search Terms:
function this parameter class interface protected property
Code

abstract class Test {
    constructor(protected foo: string) {}
    public abstract trace(): string;
}

function TraceA(this: Test): string {
    return `${this.foo}`;
}

function TraceB(this: Test): string {
    return `<pre>${this.foo}</pre>`;
}

function getTestInstance(strategy: 'A' | 'B') {
    return class StrategyTest extends Test {
        public trace = strategy === 'A' ? TraceA : TraceB;
    }
}
abstract class TestInterface<P> {
    constructor(protected foo: P) {}
    public abstract trace(): string;
}

function TraceInterfaceA<P>(this: TestInterface<P>): string {
    return `${this.foo}`; // Property 'foo' is protected and only accessible through an instance of class 'TestInterface<P>'.ts(2446)
}

function TraceInterfaceB<P>(this: TestInterface<P>): string {
    return `<pre>${this.foo}</pre>`; // Property 'foo' is protected and only accessible through an instance of class 'TestInterface<P>'.ts(2446)
}

function getTestInterfaceInstance(strategy: 'A' | 'B') {
    return class StrategyTestInterface<P> extends TestInterface<P> {
        public trace = strategy === 'A' ? TraceA : TraceB;
    }
}

Expected behavior:
If I'm not wrong, with this argument on Function, we allow only to access to public attributes, don't we? So we are supposed to get an error on the Test class implementation.
Or if the latest decision is to allow access to protected attributes, so we aren't supposed to received an error in the TestInterface example.
Actual behavior:
Without the interface, we can access to protected attributes, but when an interface is provided to the generic Class definition, we lose the ability to reach protected properties.

Playground Link:
TSPlayground
Related Issues:
#12510 Cannot access protected members when specifying 'this' type
#17694 Accessing private method with this argument specifier

@weswigham weswigham added the Bug A bug in TypeScript label Dec 25, 2018
@lsagetlethias
Copy link

lsagetlethias commented Jan 7, 2019

As the #10302 suggests and how it's implemented in #24645 , I think the good implementation is to allow access only to protected and public methods and members (but not static) in the this overload of a function.

So the second part, with Abstract is where there is a bug imho.

However, this also happen when using intersection type and union type:

class A {
    protected foo;
}

class B {
    private bar(this: A & B) {
        this.foo; // <-- error ts(2446)
    }

    private baz(this: A | B) {
        if (this instanceof A) {
            this.foo; // error
        }

        this.foo; // error

        (this as A).foo; // error
    }
}

Playground

@just-boris
Copy link

just-boris commented Feb 1, 2020

Yet another example of this issue:

export class Wrapper<T = any> {
  protected getValue() {
    return 123;
  }
}

function extractValue(this: Wrapper) {
  return this.getValue();
}

console.log(extractValue.call(new Wrapper()));

If I remove generics from the Wrapper class, it works. But once I add a generic type, it shows the error: Property 'getValue' is protected and only accessible through an instance of class 'Wrapper<any>'

Playground

Are there any known workarounds for this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants