如何在类型注释中使用函数返回的类?

时间:2018-12-18 05:04:13

标签: typescript

这是简化代码

export interface MyInterface{
    // Have no idea why I need an export here.
    // If I remove it, it gives
    // semantic error TS2451 Cannot redeclare block-scoped variable 'createClass'
}

const createClass = function () {
    return class implements MyInterface{
    }
};

const MyClass = createClass();

// this line is fine
const mi: MyInterface = new MyClass();

// this is where I concerned. It gives semantic error TS2304 Cannot find name 'MyClass'
const mc: MyClass = new MyClass();

那么如何在类型注释中使用名称MyClass? 我的TypeScript版本是3.2.2

2 个答案:

答案 0 :(得分:2)

TL; DR

MyClass添加类型定义

const MyClass = createClass();
type MyClass = InstanceType<typeof MyClass>

说明

考虑简单的类声明:

class MyClass {}
const mc: MyClass = new MyClass() 

使用class关键字声明类时,编译器知道两件事。在当前作用域中存在一个具有该类名称的值,该值能够构造该类(即MyClass构造函数),并且在当前作用域中也将存在一个与该类同名的类型表示类的实例类型(在本例中为MyClass类型)。有关值空间与类型空间的信息,请参见此answer

由于您在函数中声明了该类,即使您要为其命名,也只能在该函数内部访问它(基本作用域规则)。该接口可以访问,因为它在同一范围内(假定所有内容都在同一文件中),或者已显式导入(如果您在另一个模块中)。

使用返回的函数并将其分配给constconst MyClass = createClass();)时,您所做的只是class声明的一半,您告诉编译器存在名为MyClass的构造函数。编译器不会为MyClass的实例类型添加任何类型(为什么这样做,const的赋值通常不会引入新类型,而只会引入新值)。

简单的解决方案是完成另一半的工作,添加与返回类的实例类型名称相同的类型。这两个名称不会冲突,因为一个名称位于值空间(const)中,另一个名称位于类型空间(type)中

const MyClass = createClass();
type MyClass = InstanceType<typeof MyClass>
const mc: MyClass = new MyClass(); // Ok now.

注意 如果您不只是使用类声明,那么我假设您是在函数内部声明该类并以从问题中不明显的原因返回它。

答案 1 :(得分:1)

  

TS2451无法重新声明块作用域变量'createClass'

发生此错误是因为您在周围环境的其他位置具有createClass功能。环境手段,不受模块范围限制。至少写入一个importexport会限制您的文件范围,即使其成为一个模块。 除了导出随机接口,您还可以执行以下操作:在文件末尾添加export {}

const MyClass = createClass(); 
const mc: MyClass

在上面的代码中,您正在混合类型。具体来说,MyClass在这里是一个值,您正尝试将其用作类型。

总的来说,您正在通过函数返回一个类来做奇怪的事情。我知道您可能有自己的原因,但是通常您应该这样编写代码:

class MyClass {}
const mc: MyClass = new MyClass() // thought the type annotation is not necessary