好的,标题有点拗口,但这是我们试图实现的目标的一个例子:
interface DeferredProperty<T> {
get(): T;
}
type Deferred<T> = {
[P in keyof T]: DeferredProperty<T[P]>
};
在这里,我们使用Map类型来表达这样一个想法:一个接口类型可能会被 Package 成一个新类型,该新类型暴露与它相同的属性,只是将函数作为数据属性而不是。例如:
interface Person {
age: number,
name: string
}
var deferredPerson: Deferred<Person>;
var age = deferredPerson.age.get();
interface Vehicle {
numWheels: number,
cost: number
}
var deferredVehicle: Deferred<Vehicle>;
var cost = deferredVehicle.cost.get();
我们希望在我们系统中使很多类型可延迟,所以我们创建了一个简单的抽象基类,它可以帮助我们完成一些工作。换句话说,我们希望能够写:
abstract class BaseDeferred<T> implements Deferred<T> { //<-- note: currently not legal
// some common stuff, including concreate methods
// Maybe some abstract methods.
// protected abstract whatever(): void;
// etc.
}
然后我们可以这样做:
class DeferredPerson extends BaseDeferred<Person> {
}
class DeferredVehicle extends BaseDeferred<Vehicle> {
}
此时TypeScript会说:“嘿,DeferredPerson没有正确实现 BaseDeferred<Person>
,它缺少 age: DeferredProperty<number>
和 name: DeferredProperty<string>
。(对于DeferredVehicle也是如此)
然而,目前这还不允许,因为我们不能说: abstract class BaseDeferred<T> implements Deferred<T>
这是一个可以理解的限制。毕竟,编译器如何实际验证 BaseDeferred<T>
正在实现 Deferred<T>
,当它无法知道(在这个时候)Deferred<T>
查找类型的扩展时。
虽然可以理解,但如果这个限制有可能对抽象类型进行解除的话就更好了。因为类型是抽象的,我们希望只有在类型具体派生时才进行检查。例如,当有人写:
class DeferredPerson extends BaseDeferred<Person> {
// Now the compiler create the full type signature for BaseDeferred<Person> and then checked DeferredPerson against it.
}
--
今天的解决方法是这样做:
abstract class BaseDeferred<T> { // <-- note: no implements
}
class DeferredPerson extends BaseDeferred<Person> implements Deferred<Person> {
}
class DeferredVehicle extends BaseDeferred<Vehicle> implements Deferred<Vehicle> {
}
编译器现在适当地进行了正确的检查。这很不愉快,因为这是一个很容易错过的简单事情。由于所有子类都必须实现这种类型,我们非常希望将这一要求提高到基类,并将执行力统一应用于所有子类型。
非常感谢,我希望每个人都过得很好!我们在使用TS的过程中非常开心,尤其是(ab)利用类型系统表达一些非常有趣的东西。能够表达出更多疯狂的东西(特别是关于约束和可变参数类型),我们就越开心
9条答案
按热度按时间drnojrws1#
@DanielRosenwasser。
这个(实际上)的原因是因为TS要求实现/扩展子句只允许接口(合理)。并且TS将
SomeMappedType<SomeType>
视为接口,如果Map类型已经被完全示例化(即它已经被展开,不再包含[p in keyof T]
成员)。描述请求的更简短方式是:允许抽象类包含此Map类型成员,然后在实际子类点而不是急切地解析该成员。
m2xkgtsf2#
这里的常规建议是声明合并,例如:
这是否给你想要的行为?
jjjwad0x3#
在我们的情况下,没有。尝试这个会产生"message: '一个接口只能扩展一个类或另一个接口。'"
同样的问题存在。也就是说,用类型参数示例化的Map类型不被视为接口(可以理解)。但如果能放宽这个限制就更好了。似乎Map类型是目前唯一需要经过额外的“解析真实成员”步骤的类型。如果接口也能具备这种能力,那就太棒了。
30byixjq4#
注意:如果今天确实存在这样的系统,我们当然会很高兴使用它。但是我的TS-fu对于所有这些新功能来说还不够强大,还没有弄清楚如何使这个系统正常工作。
xqk2d5yq5#
有任何新闻吗?
我想做类似这样的事情
rseugnpd6#
@xxxTonixxx仍然无法直接实现,我建议使用一个解决方法,使用一个单独的构造函数声明来返回适当的交集:
wsxa1bj17#
它起作用了!非常感谢,很好的技巧😸
whhtz7ly8#
关于这个有什么更新吗?
c8ib6hqw9#
刚好偶然发现了这个确切的使用案例...