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:
f
as a private function?I wouldn't do this in practice, but I am curious about why TS works like this.
Thanks!
In TypeScript there are two ways to do this. The first option is to cast the object to any . The problem with this option is that you loose type safety and intellisense autocompletion. The second option is the intentional escape hatch.
Example: Declaring a class The example above declares a constructor for the class. A constructor is a special function of the class that is responsible for initializing the variables of the class. TypeScript defines a constructor using the constructor keyword. A constructor is a function and hence can be parameterized.
Creating a function in TypeScript is similar to the process in JavaScript: You use the function keyword. However, in TypeScript you also have the option to define the type of parameters and return type of the function.
TypeScript Private MethodsMethods can also be private which is useful for hiding implementation detail of how a Class works to the user of the Class.
The issue Microsoft/TypeScript#18499 discusses why private members are required when determining compatibility. The reason is: class private members are visible to other instances of the same class.
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 ofIdentity
but attempting to use it as one will crash insameAs
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With