如何从 TypeScript 函数返回一个类?

Posted

技术标签:

【中文标题】如何从 TypeScript 函数返回一个类?【英文标题】:How can I return a class from a TypeScript function? 【发布时间】: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 从工厂函数返回一个类?

【问题讨论】:

【参考方案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 接受用于定义类的参数,在这种情况下这是行不通的。

以上是关于如何从 TypeScript 函数返回一个类?的主要内容,如果未能解决你的问题,请参考以下文章

在工厂函数之外公开本地 TypeScript 类的类型

Typescript从参数返回函数类型

TypeScript 杂记十 《断言函数》

TypeScript 杂记十 《断言函数》

TypeScript 杂记十 《断言函数》

在 Typescript 中,如何声明一个返回字符串类型数组的函数?