Typescript 使用类装饰器,我可以得到类类型实例的类型吗?

Typescript 使用类装饰器,我可以得到类类型实例的类型吗?,typescript,Typescript,考虑这一点: 编辑 事实证明你所要求的是完全可能的。我已经添加了一个,但也将把这个留在这里,因为它可能包含对某人有价值的信息。这个答案建议使用运行时解决方案,新的建议使用编译时解决方案 我认为最好的选择是运行时类型检查,因为您将在decorator函数中拥有正确的类型: function DecorateClass(instantiate: (...params: any[]) => any) { return (classTarget: Function) => {

考虑这一点:

编辑 事实证明你所要求的是完全可能的。我已经添加了一个,但也将把这个留在这里,因为它可能包含对某人有价值的信息。这个答案建议使用运行时解决方案,新的建议使用编译时解决方案


我认为最好的选择是运行时类型检查,因为您将在decorator函数中拥有正确的类型:

function DecorateClass(instantiate: (...params: any[]) => any) {
    return (classTarget: Function) => {
        var instance = instantiate(/*...*/);

        if (!(instance instanceof classTarget)) {
            throw new TypeError();
        }

        // ...
    }
}
这不会产生编译时类型安全性。

请稍等一秒钟

最近,我需要一个函数的类型定义,该函数接受一个类作为参数,并返回该类的一个实例。当我想出一个答案时,这个问题很快就浮现在我的脑海里

基本上,使用一个新的类型,可以在类和它的实例之间变出一种关系,这种关系准确而完美地回答了您的问题:

function DecorateClass<T>(instantiate: (...args: any[]) => T) {
    return (classTarget: { new(...args: any[]): T }) => { /*...*/ }
}
这类似于一个新的类型(构造函数),它可以接受参数,也可以不接受参数,并返回
any
(实例)。但是,没有任何内容表明返回的必须是
any
——它也可以是泛型类型

由于我们在泛型类型参数中有从构造函数返回的内容(通过类型推断应用装饰器的类),因此我们可以使用它来定义传入回调函数的返回类型

我已经测试了装饰器,它似乎完全按照预期工作:

@DecorateClass((json: any) => {
    return new Animal(); // OK
})
@DecorateClass((json: any) => {
    return Animal; // Error
})
@DecorateClass((json: any) => {
    return "animal"; // Error
})
class Animal {
    public Name: string;
    public Sound: string;
}
这实际上使我以前的观点无效


编辑:继承 当涉及到继承时(例如:将从
实例化
返回派生类型),可分配性似乎发生了变化:您可以返回基类型,但不能返回派生类型

这是因为在泛型类型推断期间,
instantiate
返回的类型优先于
classTarget
的“返回”类型。以下问题分析了这一问题:


乍一看,这似乎是一个错误。你到底想完成什么?似乎您正在将JSON反序列化为类型实例,但无法确定。@约翰怀特:不,这只是一个基本示例。我想要完成的是在decorator函数的类型中包含类实例的类型,而不必显式地定义它。这个结构将应用于数百个类,我希望decorator的内部被类型化为类的实例,我真的不喜欢必须明确定义decorator运行的类的实例类型的想法。
function DecorateClass<T>(instantiate: (...args: any[]) => T) {
    return (classTarget: { new(...args: any[]): T }) => { /*...*/ }
}
new(...args: any[]): any
@DecorateClass((json: any) => {
    return new Animal(); // OK
})
@DecorateClass((json: any) => {
    return Animal; // Error
})
@DecorateClass((json: any) => {
    return "animal"; // Error
})
class Animal {
    public Name: string;
    public Sound: string;
}