考虑这个failing example:
deltas.dt.total_seconds() / 3600.
2000-01-01 NaN
2000-01-02 24
2000-01-03 24
2000-01-04 24
2000-01-05 24
2000-01-06 24
2000-01-07 24
2000-01-08 24
2000-01-09 24
2000-01-10 24
Freq: D, dtype: float64
这里我想约束装饰器中的匿名函数,以便始终返回相关类的实例,但由于T实际上是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;
}
而不是typeof Animal
,因此上述方法不起作用。
在泛型函数中,无论如何,我可以从类型Animal
获取类型Animal
,而不会像明确定义typeof Animal
之类的所有类型那样烦人地冗长吗?
不幸的是,不支持在通用语法中使用typeof,这是我试图让编译器理解我想要的东西的最佳选择:
function DecorateClass<TTypeOfClass, TClass>(...)
答案 0 :(得分:4)
按住该行一秒......
最近我需要一个函数的类型定义,它接受一个类作为参数,并返回该类的实例。当我想出一个solution时,很快就会出现这个问题。
基本上,使用一个新类型可以让人联想到一个类与它的实例之间的关系,它可以准确而完美地回答你的问题:
function DecorateClass<T>(instantiate: (...args: any[]) => T) {
return (classTarget: { new(...args: any[]): T }) => { /*...*/ }
}
在TypeScript中,可以使用以下签名定义任何给定的新类型:
new(...args: any[]): any
这类似于一个新的类型(构造函数),它可能会也可能不会接受参数并返回any
(实例)。但是,没有任何内容表明必须返回any
- 它也可以是泛型类型。
由于我们在构造函数函数中返回的内容(通过类型推断应用装饰器的类)在泛型类型参数中,我们可以使用它来定义传入的回调函数的返回类型。 / p>
我测试了装饰器,它似乎正如预期的那样工作:
@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无效。
当涉及继承时(例如:从instantiate
返回派生类型),可分配性似乎被翻转:您可以返回 base 类型,但不能返回< em>派生类型。
这是因为instantiate
中返回的类型优先于通用类型推断期间“返回”类型的classTarget
。以下问题检查了这个确切的问题:
答案 1 :(得分:2)
事实证明,你要求的是完全可能的。我添加了一个new answer,但也会留在这里,因为它可能包含对某人有价值的信息。这个答案表明了一个运行时解决方案,新的解决方案建议使用编译时解决方案。
我认为最好的选择是运行时类型检查,因为将在装饰器函数中具有正确的类型:
function DecorateClass(instantiate: (...params: any[]) => any) {
return (classTarget: Function) => {
var instance = instantiate(/*...*/);
if (!(instance instanceof classTarget)) {
throw new TypeError();
}
// ...
}
}
这不会产生编译时类型安全性。