说我有一个带有静态方法Test
的类.plugin
,该方法带有一个函数。该函数可以运行任意代码并扩展Test
的API。
const MyTest = Test.plugin(fooPlugin)
const test = new Test()
const myTest = new Test()
test.foo // does not exist
myTest.foo // exists
我做了a TypeScript Playground that I hope is close to working
在示例的末尾添加myTest.foo
时,.foo
键入为any
。我希望<typeof plugin>
返回我传递的plugin
函数的类型,而不是通用规范?
如果我将<typeof plugin>
替换为<typeof TestPlugin>
,那么它将按预期工作。
在不改变插件体系结构工作方式的情况下,我能做些什么来做这项工作吗?
如果我稍微更改代码(Playground link),则myTest.foo
的键入正确,但是有两个TypeScript错误。
答案 0 :(得分:1)
您修改的方法几乎是正确的,只是T = Plugin
是类型参数Plugin
的默认值T
,但是T
可以是任何其他类型,不一定Plugin
的子类型。您想说T extends Plugin
,这意味着T
必须是Plugin
的子类型。
此外,您不需要Test
中的索引签名(至少就插件体系结构而言)。这也会使丢失的成员成为错误(索引签名将隐藏这些成员):
type ApiExtension = { [key: string]: any }
export type Plugin = (instance: Test) => ApiExtension;
type Constructor<T> = new (...args: any[]) => T;
class Test {
static plugins: Plugin[] = [];
static plugin<T extends Plugin>(plugin: T) {
const currentPlugins = this.plugins;
class NewTest extends this {
static plugins = currentPlugins.concat(plugin);
}
type Extension = ReturnType<T>
return NewTest as typeof NewTest & Constructor<Extension>;
}
constructor() {
// apply plugins
// https://stackoverflow.com/a/16345172
const classConstructor = this.constructor as typeof Test;
classConstructor.plugins.forEach(plugin => {
Object.assign(this, plugin(this))
});
}
}
// Question: how to make Typescript understand that MyTest instances have a .foo() method now?
type TestPluginExtension = {
foo(): 'bar'
}
const TestPlugin = (test: Test): TestPluginExtension => {
console.log('plugin evalutes')
return {
foo: () => 'bar'
}
}
const MyTest = Test.plugin(TestPlugin)
const myTest = new MyTest()
myTest.foo()
myTest.fooo() //err