TypeScript 似乎没有推断出逆变性。这是一个说明不一致的示例:
class Base { base = "I'm base" }
class Der extends Base { der = "I'm der" }
interface Getter<E> { get(): E }
interface Setter<E> { set(value: E): void }
type Test1 = Getter<Der> extends Getter<Base> ? 'Yes' : 'No' // "Yes"
type Test2 = Getter<Base> extends Getter<Der> ? 'Yes' : 'No' // "No"
type Test3 = Setter<Der> extends Setter<Base> ? 'Yes' : 'No' // "Yes"
type Test4 = Setter<Base> extends Setter<Der> ? 'Yes' : 'No' // "Yes"
我希望Test3
是“否”,因为这也让你这样做(这只是传递Getter<Base>
给期望 a 的函数的反面Getter<Der>
):
const setBase = (setter: Setter<Base>) => setter.set(new Base())
const derSetter = {
set: (thing: Der) => console.log(thing.der.toLowerCase())
}
setBase(derSetter); // Cannot read property 'toLowerCase' of undefined!
在我的具体情况下,我正在编写一些从 HTML 元素中读取值的代码,因此有一个名为的接口Property
类似于in”或逆变的东西):Setter
set
get
interface Property<E extends Element> {
get(element: E): string
}
class ElementProperty<E extends Element, P extends Property<E>> {
constructor(
private readonly element: E,
private readonly property: P
) { }
get value() { return this.property.get(this.element) }
}
案例1(罚款):
new ElementProperty(document.head, {
get(element: Element) { return element.outerHTML.toLowerCase(); } // No prob, every element has outerHTML.
})
案例2(坏):
const element: Element = document.body;
new ElementProperty(element, {
get(element: HTMLLinkElement) { return element.href.toLowerCase(); } // The body doesn't have an href!
})
请注意,如果我在我的界面中添加一个返回 E 的方法Property
(并在实例上实现它),打字稿将正确地抱怨案例 1,但不会抱怨案例 2。
是否有一种解决方法可以用来欺骗打字稿以阻止我做类似案例 2 的事情?我不在乎我是否完全失去方差,如果可能的话,这样的事情会很好:
class ElementProperty<E extends Element, P === Property<E>> { ... }