我偶然发现了TypeScript中的奇怪情况,其中包含以下代码:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait as wait
from selenium.webdriver.support import expected_conditions as EC
wait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//td[contains(., "Fiscal Yr")]/following-sibling::td/a[img[@title="Edit Filter"]]'))).click()
正如您所看到的,function staticImplements<T>() {
return (constructor: T) => {};
}
enum FruitList {
APPLE,
BANANA,
PEAR,
}
interface FruitInterface {
fruit: FruitList;
}
abstract class Fruit implements FruitInterface {
fruit: FruitList;
constructor(fruit: FruitList) {
this.fruit = fruit;
}
}
interface AppleConstructor {
new(fruit: FruitList.APPLE): AppleInterface;
}
interface AppleInterface extends Fruit {
fruit: FruitList.APPLE;
}
class Apple extends Fruit implements AppleInterface {
fruit: FruitList.APPLE;
constructor(fruit: FruitList) {
super(fruit);
}
}
staticImplements<AppleConstructor>()(Apple);
的构造函数需要Fruit
类型的参数fruit
,子类FruitList
的构造函数也是如此,但字段{{} 1 {}} Apple
只需要枚举fruit
的值AppleInterface
,而不是enum所拥有的所有可能值,就像它的父APPLE
一样。 FruitList
期望参数FruitInterface
的类型为AppleConstructor
,用于检查fruit
static是否实现了函数{{1}的接口在最后一行。问题是,TypeScript声明它确实没有,但这怎么可能?
答案 0 :(得分:2)
您的基本问题是TypeScript类型系统有些不健全(因此您可以编写一些非类型安全的代码)。健全性是TypeScript的not a goal,但如果这个错误很常见,如果你打开issue in GitHub,他们可能会对它进行解决。我找不到你的确切问题。
这里特别不健康与不执行type variance有关。简而言之,属性读取的子类型可以是协变(子类可以缩小其只读属性),但属性写入只能是 contravariant (子类应加宽其只写属性)。如果要同时读取和写入属性,则必须不变才能成为声音。
TypeScript允许子类属性为协变。这意味着当你阅读属性时,事情通常会很好地工作,但是当你写它们时有时会发生不好的事情。
让我用更少的代码重申主要问题:
interface A {
x: string | number
}
interface B extends A {
x: number
}
const b: B = {x: 0};
const a: A = b;
a.x = "whoops"; // no error
b.x; // number at compile time, but string at runtime
b.x.toFixed(); // works at compile time, error at runtime
了解B
如何被视为A
的子类型,在您尝试将错误的内容写入其属性之前,这是正常的。人们倾向于不这样做,所以语言维护者不管它,因为防止这个问题是困难的并且真的有限(你真的想要只写属性吗?)。
在您的情况下,您的子类正在调用超类的构造函数方法来编写(更宽)属性,即使该属性已被子类缩小。这是同一个问题。
因此,这是解决特定问题的可能方法:使用泛型来指定实际约束,以便缩小/扩展仅在您期望的位置发生:
interface FruitInterface<T extends FruitList> {
fruit: T;
}
abstract class Fruit<T extends FruitList = FruitList> implements FruitInterface<T> {
fruit: T;
constructor(fruit: T) {
this.fruit = fruit;
}
}
interface AppleConstructor {
new(fruit: FruitList.APPLE): AppleInterface;
}
interface AppleInterface extends Fruit<FruitList.APPLE> {
}
class Apple extends Fruit<FruitList.APPLE> implements AppleInterface {
constructor(fruit: FruitList) {
super(fruit); // now error as you expect
}
}
要解决上述错误,您应该将构造函数更改为仅FruitList.APPLE
。
希望有所帮助;祝你好运!