我无法获得以下代码进行类型检查:
type MyFunctionConstructor<T, F extends MyFunction<T>> = new (
f: (n: number) => T
) => F;
class MyFunction<T> {
constructor(f: (n: number) => T) {
this.f = f;
}
f: (n: number) => T;
composeT(g: (t: T) => T) {
return new (this.constructor as MyFunctionConstructor<T, this>)(n =>
g(this.f(n))
);
}
composeU<U>(g: (t: T) => U) {
return new (this.constructor as MyFunctionConstructor<U, this>)(n =>
g(this.f(n)) // tsc error here, see below
);
}
}
class MyFancyFunction<T> extends MyFunction<T> {}
我收到以下错误:
Type 'this' does not satisfy the constraint 'MyFunction<U>'.
Type 'MyFunction<T>' is not assignable to type 'MyFunction<U>'.
Type 'T' is not assignable to type 'U'.
我不想按名称(即new MyFunction(...)
)调用构造函数,以便如果f
是MyFunction
子类(例如{{1 }})FancyFunction
和f.composeT(g)
也是如此。 f.composeU(g)
中用于构造函数调用的as
强制转换不适用于具有通用参数的更通用的composeT
方法。我该如何处理额外的泛型composeU
?
(进行U
类型检查的方法来自this answer。这个问题本质上是我无法在评论中进行的跟进。)
答案 0 :(得分:1)
正如我在评论中提到的那样,这实际上不能在TypeScript的类型系统中表达(无论如何从TS3.1开始)。 TypeScript代表所谓的higher-kinded types的能力非常有限。
首先,您想说MyFunction<T>
的所有子类本身必须在T
中是通用的。也就是说,您不想扩展 type MyFunction<T>
,而是扩展type constructor T ⇒ MyFunction<T>
,它将类型T
转换为{ {1}}。但是您不能这样做,因为那里有no general way to refer to type constructors in TypeScript (Microsoft/TypeScript#1213)。
接下来,假设您可以扩展MyFunction<T>
而不是T ⇒ MyFunction<T>
,则需要TypeScript的polymorphic this
尊重这一点,因此MyFunction<T>
也是类型构造函数,{ {1}}是一种具体类型。然后您can't do that either (Microsoft/TypeScript#5845)。
由于Microsoft / TypeScript#1213仍然是一个未解决的问题,并且处于“需要帮助”状态,因此希望您最终能够做到这一点。但是我不会屏住呼吸。如果您查看该问题,将会看到一些人使用的变通办法,但我认为它们太麻烦了,我无法推荐。
您可以尝试以下方法:
this
但是,如果您想捕获多态this<X>
的精神,则需要为每个子类显式缩小定义:
composeU<U>(g: (t: T) => U): MyFunction<U> {
return new (this.constructor as any)((n: number) =>
g(this.f(n));
);
}
在上面,我们使用declaration merging来缩小this
的{{1}}方法。
无论如何,希望对您有所帮助。祝你好运!