如何从TypeScript函数返回类?

Rig*_*eek 12 javascript dependency-injection angularjs typescript

我正在使用带有依赖注入库的TypeScript,它与Angular 1非常相似 - 基本上:使用依赖项作为参数注册工厂.

这就是我在ES6中注册课程的方法

export let factory = () => {
    return class Foo {}
};
Run Code Online (Sandbox Code Playgroud)

如果我在TypeScript中写相同:

export let factory = () => {
    return class Foo {}
};
Run Code Online (Sandbox Code Playgroud)

它无法编译错误

错误TS4025:导出变量'factory'已经或正在使用私有名称'Foo'.

有没有办法允许TypeScript从工厂函数返回一个类?

Nie*_*eek 8

老问题的迟到回答:

您需要在工厂方法外部定义该类,并使用“typeof”定义返回值。

class Foo {}

export const factory = (): typeof Foo => {
    return Foo;
};
Run Code Online (Sandbox Code Playgroud)

  • 有时“factory”接受用于定义类的参数,在这种情况下这不起作用。 (3认同)

Rad*_*ler 7

快速回答

改变这个:

export let factory = () => {
    return class Foo {}
};
Run Code Online (Sandbox Code Playgroud)

对此:

export let factory = () : any => {
    return class Foo {}
};
Run Code Online (Sandbox Code Playgroud)

更长的答案

可以通过tsconfig.json设置触发/强制此错误:

{
    "compilerOptions": {
        ...
        "declaration": true // this should be false or omitted
Run Code Online (Sandbox Code Playgroud)

但这不是原因,这仅仅是一个触发器。真正的原因(如此处讨论的那样,导出返回类的函数时出错:导出的变量具有或正在使用私有名称)来自Typescript编译器

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

let factory = () => { ...
Run Code Online (Sandbox Code Playgroud)

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

let factory = () : <returnType> => { ...
Run Code Online (Sandbox Code Playgroud)

在我们的案例中,TS会很快发现,返回的结果type很容易猜测:

return class Foo {} // this is returned value, 
                    // that could be treated as a return type of the factory method
Run Code Online (Sandbox Code Playgroud)

因此,以防万一我们有类似的语句(这与原始语句根本不一样,但是让我们以它为例来说明发生的情况),我们可以正确地声明返回类型:

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

这种方法行之有效,因为该类已导出,即对外部世界可见。Foo

回到我们的情况。我们希望返回类型这是不出口。然后,我们必须帮助TS编译器确定返回类型是什么。

它可能是明确的:

export let factory = () : any => {
    return class Foo {}
};
Run Code Online (Sandbox Code Playgroud)

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

export interface IFoo {}
Run Code Online (Sandbox Code Playgroud)

然后使用诸如返回类型之类的接口:

export let factory = () : IFoo => {
    return class Foo implements IFoo {}
};
Run Code Online (Sandbox Code Playgroud)

  • 好答案!现在,即使声明也可以使用:true!:)但是,您的最终建议恰好是我一开始尝试的方法-不起作用:类型'typeof Foo'不能分配给'IFoo'类型。 (4认同)
  • 我想这是真的,但在我的例子中,将“public x: boolean = false;”添加到“class Foo”仍然会导致相同的错误。检查[此](https://www.typescriptlang.org/play/#src=export%20interface%20IFoo%20%7B%0D%0A%20%20%20%20x%3A%20boolean%0D%0A% 7D%0D%0A%0D%0Aexport%20let%20ISfactory%20%3D%20()%20%3A%20IFoo%20%3D%3E%20%7B%0D%0A%20%20%20%20return% 20class%20Foo%20implements%20IFoo%20%7B%20%0D%0A%20%20%20%20%20%20%20%20public%20x%3A%20boolean%20%3D%20false%3B%0D% 0A%20%20%20%20%7D%0D%0A%7D%3B) (2认同)

Jos*_*hma 7

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

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

去游乐场看看


Mar*_*tin 2

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

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

更新的示例

export class Foo {}; 

export let factory = () => {
    return Foo;
};
Run Code Online (Sandbox Code Playgroud)

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

  • 考虑到返回动态生成的类(例如 React HOC)的用例,这并不是很有帮助。 (4认同)