让def()
返回所需的构造函数,而不是试图改变其klass
参数的类型,在概念上更清晰.尽管如此,通过将其设置为assertion function,从而将klass
参数的类型缩小到具有适当construct signature的类型,is是可能的.
可能是这样的:
function def<A extends any[], T extends object, M extends Record<keyof M, Function>>(
klass: (this: T, ...args: A) => void, fns: M & ThisType<T & M>
): asserts klass is typeof klass & (new (...args: A) => T & M) {
for (let k in fns) {
Object.defineProperty(klass.prototype, k, {
value: fns[k],
enumerable: false, writable: true, configurable: true
})
}
}
这解释了klass
具有一些generic类型A
的参数列表,并试图通过在klass
和fns
属性中使用this
parameter和the magic ThisType<T>
utility type来提供有关在klass
和fns
属性中使用this
的合理有用的经验.这个 idea 是这样的,无论this
在klass
中,无论fns
是什么类型,都将作为this
在fns
的自变量内上下文可用.
因此,以下代码将按预期进行编译和工作:
const Cat = function () { }
def(Cat, {
meow(message: string) { console.log('meow ' + message) },
})
const cat = new Cat()
cat.meow('I want food') // meow I want food
const Dog = function (this: { name: string }, name: string) {
this.name = name;
}
def(Dog, {
bark() { console.log(this.name + " barks") }
})
const dog = new Dog("Fido");
console.log(dog.name); // Fido
dog.bark(); // Fido barks
Playground link to code个