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 () {
}
};
}
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.
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
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:_
export declare class Formatter extends AbstractFormatter {
static metadata: IFormatterMetadata;
format(failures: RuleFailure[]): string;
private escapeXml; <- HERE
}
I think this is an issue, too.
Perhaps we should extend d.ts to handle this case then. Ideally the declarations file and the ts source file would be 100% compatible.
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 馃檹
Shouldn't this issue be open?
In particular, it'd be nice to be able to do something like
function foo<T>(arg: T): SomeType<T> { ... }
type Bar = {num: number}
type FooBar = ReturnType<typeof foo<Bar>>
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:
type FooBar = ReturnType<typeof foo>
But in that example, TypeScript sets the type of T
to unknown
, so the type of FooBar is SomeType<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 unknown
into it. Example on playground shows automatic unknown type for T
.
If a function foo
has a generic param, then the typeof
operator could perhaps return a generic type, and we could write:
type FooBar = ReturnType<(typeof foo)<Bar>>
That would be a breaking change to TypeScript though.
I re-opened this at https://github.com/microsoft/TypeScript/issues/36060
Interesting fix:
Moving the mixin to its own file and doing a default
export works:
type Constructor<T = {}> = new (...args: any[]) => T
export default <T extends Constructor>(base: T) => class SomeClass extends base {
protected something: boolean = false
}
While a named export throws the error:
type Constructor<T = {}> = new (...args: any[]) => T
export const mixin = <T extends Constructor>(base: T) => class SomeClass extends base {
protected something: boolean = false
}
Most helpful comment
Perhaps we should extend d.ts to handle this case then. Ideally the declarations file and the ts source file would be 100% compatible.