英文:
Is it possible to implement Typescript class which has a protected property?
问题
I'm trying to mock a class of a third-party library which contains a protected
property and have encountered an error message.
Here's a small reproducible example:
class WithProtected {
protected property: number = 1
}
class Derived implements WithProtected {
property = 3
}
This results in the following error message:
Class 'Derived' incorrectly implements class 'WithProtected'. Did you mean to extend 'WithProtected' and inherit its members as a subclass?
Property 'property' is protected but type 'Derived' is not a class derived from 'WithProtected'.(2720)
I'm facing challenges with mocking because the third-party library is Cocos Creator and is not located in the node_modules
directory. TypeScript is only working with it due to a path
entry in the tsconfig.json
file of the project.
Since I cannot directly import from the library, I have to write a significant amount of mocks without importing members directly from 'cc,' using import type {} from 'cc'
. This prevents me from extending these classes and implementing only the mocks.
If I could find a way to implement
a class that contains a private property, it would be very helpful.
英文:
I'm trying to mock a class of a third party library which contains a protected
property and have got an error message.
here's a small reproducible example:
class WithProtected {
protected property: number = 1
}
class Derived implements WithProtected {
property = 3
}
which outputs the following error message:
Class 'Derived' incorrectly implements class 'WithProtected'. Did you mean to extend 'WithProtected' and inherit its members as a subclass?
Property 'property' is protected but type 'Derived' is not a class derived from 'WithProtected'.(2720)
I'm kinda stuck to this mocking because the third party lib is Cocos Creator and doesn't live in the node_modules
library. The only way Typescript is working with it is because it is linked via a path
entry in the tsconfig.json
file of the project.
So I'm not able to use the mocking out of the box from jest.
Also, as I cannot import directly from the lib itself, I have to write a fair amount of mock without importing members directly from 'cc' but with the import type {} from 'cc'
which doesn't allow me to extend
said classes and implement only the mocks.
Maybe too much details on this but if I could at least find a way to implement
a class which contains a private prop, this would probably save me!
答案1
得分: 1
Classes with private
or protected
methods are intentionally incompatible with other classes or types, even if they are structurally identical. This is one of the few places in TypeScript where types are treated nominally instead of structurally, and so the problem you're facing is considered a feature. If you need compatibility with a private
/protected
property, you need your type to originate from the same declaration site.
This implies that you'll never get another class
statement to work directly.
Instead, you could use type assertions on a class
expression to claim that your new class is compatible with the other one. Maybe like this:
import type { WithProtected } from "./theLib";
const MyWithProtected = (class {
property = 2;
} as any) as new () => WithProtected;
That compiles with no error (although the compiler is resistant and you need to use two type assertions to overcome its objections). Now you have a MyWithProtected
class constructor that the compiler believes makes instances of your imported WithProtected
type.
And then if you need to make subclasses via extends
you can do so:
class Derived extends MyWithProtected {
property = 3;
}
英文:
Classes with private
or protected
methods are intentionally incompatible with other classes or types, even if they are structurally identical. This is one of the few places in TypeScript where types are treated nominally instead of structurally, and so the problem you're facing is considered a feature. If you need compatibility with a private
/protected
property, you need your type to originate from the same declaration site.
This implies that you'll never get another class
statement to work directly.
Instead, you could use type assertions on a class
expression to claim that your new class is compatible with the other one. Maybe like this:
import type { WithProtected } from "./theLib";
const MyWithProtected = (class {
property = 2;
} as any) as new () => WithProtected;
That compiles with no error (although the compiler is resistant and you need to use two type assertions to overcome its objections). Now you have a MyWithProtected
class constructor that the compiler believes makes instances of your imported WithProtected
type.
And then if you need to make subclasses via extends
you can do so:
class Derived extends MyWithProtected {
property = 3;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论