Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot create declaration files from static factory class returned from a function. #24226

Open
rjamesnw opened this issue May 17, 2018 · 1 comment
Labels
Bug A bug in TypeScript
Milestone

Comments

@rjamesnw
Copy link

rjamesnw commented May 17, 2018

TypeScript Version:
2.8 and 2.9

Search Terms:
Cannot create declaration files from static factory class returned from a function.

Code
(pay special attention to class SomeClass)

namespace Test {
    export interface IType<TInstance = object> {
        new(...args: any[]): TInstance;
    }
	
    export function ClassFactory<TBaseClass extends IType, TClass extends any, TFactory extends any, TNamespace extends object>
        (namespace: TNamespace, base: { $__type: TBaseClass }, getType: (base: TBaseClass) => [TClass, TFactory], exportName?: keyof TNamespace, addMemberTypeInfo = true)
        : TClass & TFactory & { $__type: TClass } {
        return null;
    }

    export function FactoryBase<TBaseFactory extends IType>(baseFactoryType: TBaseFactory) {
        return class FactoryBase {
            static 'new'?(...args: any[]): any;
            static init?(o: object, isnew: boolean, ...args: any[]): void;
        };
    }

    function TestDec<T>(c:T):T { return null; }

    export namespace Loader {
        export var _SomeClass = ClassFactory(Loader, void 0,
            (base) => {
                @TestDec
                class SomeClass {
                     static readonly SomeClassFactory = class Factory extends FactoryBase(null) {
                        static 'new'(): SomeClass { return null; }
                        static init(o: SomeClass, isnew: boolean) {
                        }
                    };
                }
                return [SomeClass, SomeClass["SomeClassFactory"]];
            }
        );
    }
}

The code compiles and runs OK, no problems. The issue is that when I enable the flag to export declarations as well I get this error:

Scripts/testscript.ts(20,20): error TS4025: Exported variable '_SomeClass' has or is using private name 'SomeClass'.

Expected behavior:

It is expected that the d.ts files are generated without giving me issues. Without declarations it compiles fine. The partial workaround (see below) makes the error pointless.

Actual behavior:

Error message (see above).

Other Details:
This works:

namespace Test {
    export interface IType<TInstance = object> {
        new(...args: any[]): TInstance;
    }
	
    export function ClassFactory<TBaseClass extends IType, TClass extends any, TFactory extends any, TNamespace extends object>
        (namespace: TNamespace, base: { $__type: TBaseClass }, getType: (base: TBaseClass) => [TClass, TFactory], exportName?: keyof TNamespace, addMemberTypeInfo = true)
        : TClass & TFactory & { $__type: TClass } {
        return null;
    }

    export function FactoryBase<TBaseFactory extends IType>(baseFactoryType: TBaseFactory) {
        return class FactoryBase {
            static 'new'?(...args: any[]): any;
            static init?(o: object, isnew: boolean, ...args: any[]): void;
        };
    }

	function TestDec<T>(c:T):T { return null; }
	
    export namespace Loader {
        export var _SomeClass = ClassFactory(Loader, void 0,
            (base) => {
                // @TestDec <- CANNOT ADD DECORATORS, CANNOT SUPPORT ANGULAR, ETC., WITHOUT UGLY WORKAROUNDS
                var c = class SomeClass {
                     static readonly SomeClassFactory = class Factory extends FactoryBase(null) {
                        static 'new'(): SomeClass { return null; }
                        static init(o: SomeClass, isnew: boolean) {
                        }
                    };
                };
                return [c, c["SomeClassFactory"]];
            }
        );

    }
}

Notice however that I lost the @TestDec decorator doing this above (YES, I know a decorator is just a function). Not a very pleasant experience for Angular users.

Now, the following code I change SomeClassFactory to protected and it works ONLY if declarations are turned off; HOWEVER, when declarations are turned are on, this also fails with error: testscript.ts(22,20): error TS4094: Property 'SomeClassFactory' of exported class expression may not be private or protected. It's protected for a reason - I do not want people to see it in the code completion list on the exported property.

namespace Test {
    export interface IType<TInstance = object> {
        new(...args: any[]): TInstance;
    }
	
    export function ClassFactory<TBaseClass extends IType, TClass extends any, TFactory extends any, TNamespace extends object>
        (namespace: TNamespace, base: { $__type: TBaseClass }, getType: (base: TBaseClass) => [TClass, TFactory], exportName?: keyof TNamespace, addMemberTypeInfo = true)
        : TClass & TFactory & { $__type: TClass } {
        return null;
    }

    export function FactoryBase<TBaseFactory extends IType>(baseFactoryType: TBaseFactory) {
        return class FactoryBase {
            static 'new'?(...args: any[]): any;
            static init?(o: object, isnew: boolean, ...args: any[]): void;
        };
    }

	function TestDec<T>(c:T):T { return null; }
	
    export namespace Loader {
        export var _SomeClass = ClassFactory(Loader, void 0,
            (base) => {
				// @TestDec <- CANNOT ADD DECORATORS, CANNOT SUPPORT ANGULAR, ETC., WITHOUT UGLY WORKAROUNDS
                var c = class SomeClass {
                     protected static readonly SomeClassFactory = class Factory extends FactoryBase(null) {
                        static 'new'(): SomeClass { return null; }
                        static init(o: SomeClass, isnew: boolean) {
                        }
                    };
                };
                return [c, c["SomeClassFactory"]];
            }
        );

    }
}

It's very frustrating to have it compile and run PERFECTLY, but then fail to generate declaration files. I keep getting blocked at every turn and it's driving me nuts lol. It's days like this I just want to switch back to pure JavaScript and save time (except then I realize all the bugs I'll probably get which would offset any time saved coding it lol ... :*( ).

@rjamesnw rjamesnw changed the title Cannot create declaration files from class returned from a function. Cannot create declaration files from static factory class returned from a function. May 18, 2018
@mhegazy mhegazy added this to the TypeScript 3.0 milestone May 21, 2018
@mhegazy mhegazy added the Bug A bug in TypeScript label May 21, 2018
@mhegazy mhegazy modified the milestones: TypeScript 3.0, TypeScript 3.1 Jul 2, 2018
@RyanCavanaugh RyanCavanaugh modified the milestones: TypeScript 3.1, Future Aug 23, 2018
@trusktr
Copy link
Contributor

trusktr commented Dec 21, 2019

Please see #35822

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants