typescript - 使用类装饰器,我可以获得类类型实例的类型吗?

标签 typescript

考虑这个 failing example :

function DecorateClass<T>(instantiate: (...params:any[]) => T){
    return (classTarget:T) => { /*...*/ }
}

@DecorateClass((json:any) => {
    //Purely example logic here, the point is that it have to return
    //an instance of the class that the decorator runs on.
    var instance = new Animal();
    instance.Name = json.name;
    instance.Sound = json.sound;
    return instance;
})
class Animal {
    public Name:string;
    public Sound:string;
}

在这里,我想限制装饰器中的匿名函数始终返回相关类的实例,但上面的方法不起作用,因为 T 实际上是 typeof Animal而不是 Animal .

在通用函数中,无论如何我可以得到类型 Animal来自类型 typeof Animal而不会像 function DecorateClass<TTypeOfClass, TClass>(...) 这样显式定义所有类型那样冗长烦人?

不幸的是,不支持在通用语法中使用 typeof,这是我试图让编译器理解我想要的东西的最佳选择:

function DecorateClass<T>(instantiate: (json:any) => T){
    return (classTarget:typeof T) => { /*...*/  } // Cannot resolve symbol T
}

最佳答案

稍等片刻...

最近我需要一个函数的类型定义,它接受一个类作为参数,并返回该类的一个实例。当我想出一个 solution ,我很快就想到了这个问题。

基本上,使用可新类型可以在类与其实例之间建立关系,从而准确且完美地回答您的问题:

function DecorateClass<T>(instantiate: (...args: any[]) => T) {
    return (classTarget: { new(...args: any[]): T }) => { /*...*/ }
}

解释

在 TypeScript 中,任何给定的新类型都可以使用以下签名定义:

new(...args: any[]): 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;
}

这实际上使我之前的 answer 无效.


编辑:继承

当涉及到继承时(例如:从实例化返回一个派生类型),可分配性似乎被翻转了:你可以返回一个base类型,但是不是派生类型。

这是因为在泛型类型推断期间,instantiate 的返回类型优先于 classTarget 的“返回”类型。以下问题检查了这个确切的问题:

关于typescript - 使用类装饰器,我可以获得类类型实例的类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35373269/

相关文章:

javascript - Angular2 - 选中 ngFor 和 react 形式中的复选框

从父组件到子组件的 Angular 传递数组

typescript - 如何实现具有多个函数调用签名的 typescript 接口(interface)

typescript - 运算符 === 将始终返回 'false',因为类型没有重叠

typescript - 如何删除所有未使用的参数/导入、添加缺失的导入以及通过脚本进行美化

javascript - 如何处理调用在 defer.resolve() 内返回 Promise 的函数?

typescript - 如何将秒数转换为angular2中的时间字符串?

angular - 如何从子组件打开 MdSidenav?

TypeScript - 为什么数组 .includes() 期望 searchElement 为 "never"类型?

reactjs - React Typescript Hook 错误 - 该表达式不可调用