Skip to content

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

Open
@rjamesnw

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

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