TypeScript class implements class with private functions

喜夏-厌秋 提交于 2021-02-16 04:39:01

问题


I was exploring the possibility of having a class implementing a class in TypeScript.

Hence, I wrote the following code Playground link:

class A {
    private f() { console.log("f"); }
    public g() { console.log("G"); }
}

class B implements A {
    public g() { console.log("g"); }
}

And I got the error: Class 'B' incorrectly implements class 'A' --- property 'f' is missing in type 'B' coupled with a suggestion that I actually meant extends.

So I tried to make a private field called f (public didn't work as it detects they have different access modifiers) Playground link

Now I get the error: Class 'B' incorrectly implements class 'A'. Types have separate declarations of a private property 'f'; this leaves me very confused:

  • why do private members even matter - if I implement the same algorithm using different data structures, will I have to declare something named the same just for the sake of type checking?
  • why do I get the error when implementing f as a private function?

I wouldn't do this in practice, but I am curious about why TS works like this.

Thanks!


回答1:


The issue Microsoft/TypeScript#18499 discusses why private members are required when determining compatibility. One remark by @RyanCavanaugh is particularly relevant and illuminating:

Allowing the private fields to be missing would be an enormous problem, not some trivial soundness issue. Consider this code:

class Identity { private id: string = "secret agent"; public sameAs(other: Identity) { return this.id.toLowerCase() === other.id.toLowerCase(); } } class MockIdentity implements Identity { public sameAs(other: Identity) { return false; } }
MockIdentity is a public-compatible version of Identity but attempting to use it as one will crash in sameAs when a non-mocked copy interacts with a mocked copy.

Just to be clear, here's where it would fail:

const identity = new Identity();
const mockIdentity = new MockIdentity();
identity.sameAs(mockIdentity); // boom!

So, there are good reasons why you can't do it.


As a workaround, you can pull out just the public properties of a class with a mapped type like this:

type PublicPart<T> = {[K in keyof T]: T[K]}

And then you can have B implement not A but PublicPart<A>:

class A {
    private f() { console.log("f"); }
    public g() { console.log("G"); }
}

// works    
class B implements PublicPart<A> {
    public g() { console.log("g"); }
}

Hope that helps; good luck!




回答2:


In this case it is not possible with the current typescript specifications. There is a tracked issue for this but it is closed.

Suggestion: Permit an implementing class to ignore private methods of the implementee class.


See also Extending vs. implementing a pure abstract class in TypeScript




回答3:


This is fundamentally due to the fact the visibility of private members are scoped to the type, and not the instance. Meaning that all objects of the type T have access to the privates of other objects of type T.

This is not a problem in nominatively typed languages as all instances of T inherits the implementation of T, but since typescript is structurally typed, it mean that we can not assume that all instances that fulfill T have the implementation of the class that declares type T.

This means that privately scoped members have to be a part of the public contract of the type, otherwise an object of the structural type T could call a non-existing private member of another object with the same structural type.

Being forced to have privates being a part of a public type contract is bad, and could have been avoided by scoping privates to the instance and not the type.




回答4:


The current solution with out-of-the-box support from Typescript is simply

class A {
    private f() { console.log("f"); }
    public g() { console.log("G"); }
}

class B implements Pick<A, keyof A> {
    public g() { console.log("g"); }
}

Explanation: keyof A only returns public properties (and methods) of A, and Pick will then down trim A to only its public properties and their respective type.



来源:https://stackoverflow.com/questions/48953587/typescript-class-implements-class-with-private-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!