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

[ts] 'private' modifier cannot appear on a type member. #25163

Closed
msudgh opened this issue Jun 22, 2018 · 12 comments
Closed

[ts] 'private' modifier cannot appear on a type member. #25163

msudgh opened this issue Jun 22, 2018 · 12 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@msudgh
Copy link

msudgh commented Jun 22, 2018

I declared an interface with private property method as the following snippet:

export interface TestInterface {
  auth: () => Promise<any>
  private findGist: (page: number) => Promise<any>
}

Butt i got error with the context [ts] 'private' modifier cannot appear on a type member. in vscode.
What's wrong?

@j-oliveras
Copy link
Contributor

You can only use private inside a class.

@RikkiGibson
Copy link
Member

private means it should only be visible to members declared on the same type--but since interface members don't have implementations, there's no way to reference the private property. So it's just not allowed.

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Jun 22, 2018
@RyanCavanaugh
Copy link
Member

It looks like this is a question rather than a bug report. This issue tracker is for tracking bugs and active work on TypeScript itself, rather than a general forum for programmers using TypeScript to get help or ask questions.

You can ask questions on sites like Stack Overflow. We are not able to provide one-on-one support on the issue tracker. Next time, please read the issue template carefully - it has important information on what kinds of reports can be acted on here, as well as links to useful TypeScript resources. Thanks!

@MutableLoss
Copy link

MutableLoss commented Oct 27, 2018

I think there is a bit of confusion that leads up to this error. If the members defined in the class are private, and these same members are used in the interface, TS will not compile and complain that these members are not set as private.

interface IInterface {
  memberOne: string
  memberTwo: string
}

class TestClass implements IInterface {
  private memberOne!: string
  private memberTwo!: string
}

Using the above will yield the following error:

Class 'TestClass' incorrectly implements interface 'IInterface'.
  Property 'memberOne' is private in type 'TestClass' but not in type 'IInterface'.

So if setting access modifiers on interfaces is not possible why does TS give this sort of error which implies there are? I'm guessing the overall idea is to not add private members in an interface, and if that's the case, maybe TS could offer an error to imply something along those lines instead?

@andykais
Copy link

andykais commented Feb 1, 2019

do we currently have any way to mark interface properties as protected or private? Currently this is the best I can do:

interface TestInterface {
  prop1: number
  prop2?: string
}

class TestClass {
  protected prop1: TestInterface['prop1']
  protected prop2: TestInterface['prop2']
}

though this isnt a great solution because if TestInterface had extra properties, no error would be thrown if they were missing from TestClass

@takahser
Copy link

takahser commented Feb 14, 2019

I agree with @3desprit
Why is this happening?

edit

Apparently,

Interfaces define "public" contracts and as such it doesn't make sense to have protected or private access modifier on interfaces, which are more of a, let's call it, implementation detail. As such you can't do what you want with an interface.

see original post on SO

@trusktr
Copy link
Contributor

trusktr commented Jun 30, 2019

What about protected? Seems like this is obviously needed (as opposed to private).

I'm using types for mixin classes (it is inevitable to have to step around the class system and use types to make them work fully). And I'd like to be able to specify protected in some interfaces which I'm using along Constructor types to create the types minimal types of expected classes being passed to the mixins.

@trusktr
Copy link
Contributor

trusktr commented Jun 30, 2019

For example, it is necessary to use interfaces/types (and not class) in order to make a mixin class understand what methods a base class might possibly have:

type PossibleCustomElement<T extends HTMLElement> = T & {
    protected connectedCallback?(): void // contrived example
    disconnectedCallback?(): void
    adoptedCallback?(): void
    attributeChangedCallback?(name: string, oldVal: string | null, newVal: string | null): void
}

// This is a mixin only for Web Components! :)
export function WithUpdateMixin<T extends Constructor<HTMLElement>>(Base: T) {
    class WithUpdate extends Base as unknown as Constructor<PossibleCustomElement<HTMLElement>> {
        protected connectedCallback() {
            if (super.connectedCallback) super.connectedCallback()
        }
    }
}

And so you see, I want to be able to define certain possibly-existing method/properties from the Base class (which is constrained by type T), and if any of those methods are protected, then now they will all be public because there's no way to specify it in the mixin.

For sake of argument, let's imagine that connectedCallback is a protected method in some subclasses of HTMLElement; suppose this is a convention in HTML world (I know, it actually isn't, this is just an example). Then it'd be convenient if all I had to do was add the protected keyword for it to just work.

@trusktr
Copy link
Contributor

trusktr commented Jun 30, 2019

Here's what we can do to make a type with access modifiers, although it emits an unused runtime class (based on some actual code I have, much omitted):

type Constructor<T = object, A extends any[] = any[]> = new (...a: A) => T
function Constructor<T = object>(Ctor: Constructor<any>) {
    return (Ctor as unknown) as Constructor<T>
}

// using a `class` instead of `interface` or `type`!
class PossiblyWebComponent {
    protected childConnectedCallback?(child: Element): void
    protected childDisconnectedCallback?(child: Element): void
    protected _isPossiblyDistributedToShadowRoot?: boolean
    protected _distributedParent?: TreeNode 
}

function AwesomeMixin<T extends Constructor>(Base: T) {
    const Parent = SomeOtherMixin(Constructor<PossiblyWebComponent>(Base))

    class Awesome extends Parent {
        protected childConnectedCallback(child: Element) {
            if (super.connectedCallback) super.connectedCallback(child)
        }

        // ...
    }

    return Awesome as Constructor<Awesome & InstanceType<T>>
}

It is possible to run the code through some Babel or Webpack plugin to snip unused code.

EDIT: Or maybe just use declare to prevent the runtime output. I almost forgot about that.

@Leandro-Hespanhol
Copy link

Leandro-Hespanhol commented Apr 11, 2022

I think the solution lies in 'getters', here is an example:

interface IFighter {
   strength: number;
   dexterity: number;
}

class Character implements IFighter {
  protected _strength: number;
  protected _dexterity: number;
  ...
  get strength() { return this._strength }
  get dexterity() { return this._dexterity }
}

That way you can implement an interface and still keep class attributes protected.

@Autumnlight02
Copy link

@Leandro-Hespanhol Thank you!

@ThaJay
Copy link

ThaJay commented Mar 13, 2023

Type script seems more and more time consuming and convoluted as I learn it on an ever deepening level

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests