我有一个Users
类,我正在从文件Users.ts
导出
export default class Users {}
然后我从另一个文件Users.ts
中导出index.ts
:
// classes
export {default as Users} from './Users'
我有第三个文件Foo.ts
,我想在其中动态实例化index.ts
中所有导出的类,并将它们作为属性添加到该类:
import * as classes from './index'
class Foo {
constructor() {
const httpClient = new HttpClient()
}
_addClasses() {
for (const class in classes) {
this[class] = new classes[class](this.httpClient);
}
}
}
我的问题是,如何为Foo
添加正确的类型,以便可以在IDE中为.users
获得正确的自动补全功能,例如:
new Foo(new HttpClient).users
答案 0 :(得分:1)
该问题的第一部分是创建一个包含导入模块实例类型的新类型。为此,我们将使用预定义的条件类型InstanceType
来提取类的实例类型。要获取模块的类型,我们将使用typeof classes
。将其全部包装为映射类型,我们得到:
type ClassInstances = {
[P in keyof typeof classes]: InstanceType<typeof classes[P]>
}
// For the example above this is equivalent to
type ClassInstances = {
Users: classes.Users;
}
现在,我们需要将这些新属性添加到类中。为此,无需显式定义它们,我们可以使用一个空的类表达式作为Foo
的基类,并断言该空类返回的实例具有这些成员(实际上不是,但是我们和这些成员_addClasses
中的所有内容都可以解决)。全部放在一起,我们得到:
import * as classes from './index';
type ClassInstances = {
[P in keyof typeof classes]: InstanceType<typeof classes[P]>
}
class Foo extends (class {} as new () => ClassInstances) {
httpClient: HttpClient;
constructor() {
super();
this.httpClient = new HttpClient()
this._addClasses();
}
_addClasses() {
for (const cls of Object.keys(classes) as Array<keyof typeof classes>) {
this[cls] = new classes[cls](this.httpClient);
}
}
}
new Foo().Users // ok now name is the same as the name used in the export in index.ts so it's upper case. No string manipulation on string properties.