TypeScript: False error TS4094: ... exported class expression may not be private or protected.
TypeScript Version: 3.3.3333
Code
src/test.ts:
export function test () {
return class {
private privateMember () {
}
};
}
tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
}
Expected behavior: No compilation error.
Actual behavior: Compiler prints error: $ tsc src/test.ts(1,17): error TS4094: Property ‘privateMember’ of exported class expression may not be private or protected.
Playground Link: not possible to provide.
Workaround
Declare the return type explicitly:
export function test (): new() => Object {
return class {
private privateMember () {
}
};
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 26
- Comments: 22 (1 by maintainers)
Commits related to this issue
- Create Angular mixins for fractional-width columns and groupable columns (#1587) # Pull Request ## 🤨 Rationale Resolves #1211 In Angular, we didn't have a solution for the code duplication... — committed to ni/nimble by mollykreis 9 months ago
- https://github.com/microsoft/TypeScript/issues/30355 — committed to roobscoob/nnfileabstraction by Sanae6 7 months ago
The error message didn’t accidently write itself… exported anonymous classes can’t have private or protected members if declaration emit is enabled, because there’s no way to represent that in a .d.ts file.
Perhaps we should extend d.ts to handle this case then. Ideally the declarations file and the ts source file would be 100% compatible.
Shouldn’t this issue be open?
It is currently not possible to generate declaration files when using a class mixin pattern, even if that pattern would otherwise compile and type-check just fine. It would be nice to have support for this 🙏
here is how you can fix it, instead of
do
Interesting fix:
Moving the mixin to its own file and doing a
defaultexport works:While a named export throws the error:
It is possible to use private in declaration files. In my project, for example, I found a lot of them in node_modules folder: tslint/lib/formatters/checkstyleFormatter.d.ts:
Another solution can be to just use the ES2020 private fields if you ever encounter this problem. This will avoid you to define a return type, which can be annoying if your mixin is quite complex :
Solution: Just give the function a proper return type declaration. This one then needs to be an indirect connection, e.g. an interface describing the prototype of the returned class. Then, the compiler stops complaining 😃
In particular, it’d be nice to be able to do something like
I get what you’re saying, that
foo<Bar>is already a type, so typeof doesn’t make sense. But I think you get what’s missing.This is valid:
But in that example, TypeScript sets the type of
Ttounknown, so the type of FooBar isSomeType<T>.Basically, it just intuitively seems like there should be some way to pass a generic arg there, but we can’t, and TypeScript automatically sticks
unknowninto it. Example on playground shows automatic unknown type forT.I think this is an issue, too.
isn’t it a bug then? So it’s doing exactly same, but with two files instead of one. I’m quite surprised to see that this issue is Closed while indeed it must not and should be fixed
Although use
#to declare private member can avoid this declaration error, it will make the property not readable, plus it can not replaceprotected. I only want some method or property not overridable in some cases.Just play with Omit type 😎. Just a example with vitest :
NB: If you don’t know the private members of the class, just put never as second parameter of Omit.