【问题标题】:How can I return a class from a TypeScript function?如何从 TypeScript 函数返回一个类?
【发布时间】:2016-05-20 17:46:29
【问题描述】:

我正在使用 TypeScript 和一个与 Angular 1 非常相似的依赖注入库 - 基本上:注册一个工厂,将你的依赖项作为参数

这就是我在 ES6 中注册类的方式

export let factory = () => {
    return class Foo {}
};

如果我在 TypeScript 中写同样的话:

export let factory = () => {
    return class Foo {}
};

编译失败,报错

错误 TS4025:导出的变量“工厂”具有或正在使用私有名称“Foo”。

有什么方法可以让 TypeScript 从工厂函数返回一个类?

【问题讨论】:

    标签: javascript angularjs dependency-injection typescript


    【解决方案1】:

    您还需要导出类,以便方法的使用者可以访问该类型。

    通常,工厂将返回一个实例而不是类或构造函数。

    更新示例

    export class Foo {}; 
    
    export let factory = () => {
        return Foo;
    };
    

    使用 ES6,您不需要导出类类型,但使用 TypeScript,您绝对应该导出类型签名。

    【讨论】:

    • 考虑到返回动态生成的类(例如 React HOC)的用例,这并不是很有帮助。
    • 最初的问题是关于在打字稿中实现工厂模式(使用 AngularJS),并解决编译器错误。它没有说明生成动态生成的类。
    • @Martin 这个问题字面上只包含一个动态类的例子。
    • @MarcJ.Schmidt 是的,那是因为 ES6 是一种动态语言,问题是如何在 TypeScript 中做到这一点——它添加了类型签名。
    【解决方案2】:

    您是否正在寻找从函数返回的类类型?下面是一段代码 sn-p 我们如何在 TypeScript 中实现与其他语言类似的工厂。

        class Greeter {
        greeting: string;
        constructor(message: string) {
            this.greeting = message;
        }
        greet() {
            return "Hello, " + this.greeting;
        }
    }
    class Factory{
        getObject(msg:string): Greeter {
            return new Greeter(msg);
        }
    }
    var greeter = new Factory().getObject("Hi");
    console.log(greeter.greet());
    

    【讨论】:

      【解决方案3】:

      我正在为同样的错误而苦苦挣扎。我的解决方案是删除

      "declaration": true
      

      来自tsconfig.json 或将其设置为false

      【讨论】:

        【解决方案4】:

        快速解答

        改变这个:

        export let factory = () => {
            return class Foo {}
        };
        

        到那个:

        export let factory = () : any => {
            return class Foo {}
        };
        

        更长的答案

        此错误可能由 tsconfig.json 设置触发/强制:

        {
            "compilerOptions": {
                ...
                "declaration": true // this should be false or omitted
        

        但这不是原因,它只是一个触发器。真正的原因(在这里讨论Error when exporting function that returns class: Exported variable has or is using private name)来自 Typescript 编译器

        当 TS 编译器发现这样的语句时

        let factory = () => { ...
        

        它必须开始猜测返回类型是什么,因为缺少该信息(检查 : <returnType> 占位符)

        let factory = () : <returnType> => { ...
        

        在我们的例子中,TS 会很快发现,返回的type 很容易猜到:

        return class Foo {} // this is returned value, 
                            // that could be treated as a return type of the factory method
        

        所以,如果我们有类似的陈述(这与原始陈述完全不一样,但让我们试着用它作为一个例子来澄清会发生什么) 我们可以正确声明返回类型:

        export class Foo {} // Foo is exported
        export let factory = () : Foo => { // it could be return type of export function
            return Foo
        };
        

        这种方法会奏效,因为 Foo 已导出,即对外可见。

        回到我们的案例。 我们希望返回类型,该类型未导出。然后,我们必须帮助 TS 编译器决定返回类型是什么。

        它可以是任何明确的:

        export let factory = () : any => {
            return class Foo {}
        };
        

        但更好的是有一些公共接口

        export interface IFoo {}
        

        然后使用返回类型这样的接口:

        export let factory = () : IFoo => {
            return class Foo implements IFoo {}
        };
        

        【讨论】:

        • 好答案!现在它甚至可以使用声明:true! :) 但是,您的最终建议正是我在开始时所做的尝试 - 这不起作用:类型 'typeof Foo' 不可分配给类型 'IFoo'。
        • @MiB 我想说,这是另一个问题。检查这个操场example ...显示这样的问题..如果IFoo作为接口需要一些东西..Foo没有实现......在那个例子中IFoo {x:boolean}需要x 但是类没有它class Foo implements IFoo {}希望它有点帮助
        • 我想这是真的,但在我的情况下,将 public x: boolean = false; 添加到 class Foo 仍然会导致相同的错误。检查this
        【解决方案5】:

        我认为这是一个正确的方法:

        export let factory = () => {
             class Foo {/* ... */}
             return Foo as (new () => { [key in keyof Foo]: Foo[key] })
        };
        

        Check it out on playground

        【讨论】:

          【解决方案6】:

          我发现separately provided solution 很满意:

          export class MyClass {
             ...
          }
          
          export type MyClassRef = new (...args: any) => MyClass;
          

          鉴于该签名,我可以使用 MyClassRef 作为一种返回值:

          exposeMyClass(): MyClassRef {
              return MyClass;
          }
          

          【讨论】:

            【解决方案7】:

            旧问题的最新答案:

            您需要在工厂方法之外定义类并使用'typeof'定义返回值。

            class Foo {}
            
            export const factory = (): typeof Foo => {
                return Foo;
            };
            

            【讨论】:

            • 为什么这不是公认的答案?谢谢@Niels Steenbeek
            • 有时factory 接受用于定义类的参数,在这种情况下这是行不通的。
            猜你喜欢
            • 2020-04-27
            • 1970-01-01
            • 2021-05-28
            • 1970-01-01
            • 2020-08-31
            • 1970-01-01
            • 1970-01-01
            • 2020-02-11
            • 1970-01-01
            相关资源
            最近更新 更多