Skip to content

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

Description

@rjamesnw

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 ... :*( ).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions