【问题标题】:The problem with interfaces that extends the interface扩展接口的接口问题
【发布时间】:2020-09-07 05:46:36
【问题描述】:

我希望实现 Observer 接口的类也实现 Comparable 接口,我该怎么做?

interface Comparable<T> {
    equals: (item: T) => boolean;
}

interface Observer extends Comparable<Observer> {
    notify: () => void
}

class TestA implements Observer {
    private name = '';

    equals = (item: TestA) => {
        return this.name === item.name
    }

    notify = () => {}
}

class TestB implements Observer {
    private name = '';

    equals = (item: TestB) => {
        return this.name === item.name
    }

    notify = () => {}
}

错误:

TS2416:类型“TestA”中的属性“等于”不能分配给基本类型“观察者”中的相同属性。类型 '(item: TestA) => boolean' 不可分配给类型 '(item: Observer) => boolean'。参数“item”和“item”的类型不兼容。 “观察者”类型中缺少属性“名称”,但在“TestA”类型中是必需的。

但是,TestA实现了Observer接口,为什么不兼容呢?

当然,我可以这样写:

class TestA implements Observer {
    private name = '';

    equals = (item: Observer) => {
        return this.name === item.name
    }

    notify = () => {}
}

然后我得到这样一个错误,此外,这并不完全正确,因为我只想比较这个类的对象:

“观察者”类型上不存在属性“名称”。

怎么做才对? “打字稿”:“^3.9.2”

【问题讨论】:

    标签: javascript typescript


    【解决方案1】:

    在 TestA 类和 TestB 类中将 equals(item: TestA)equals(item:TestB) 更改为 equals(item : Observer)

    因为 Comparable 类型被指定为 Observable。

    在 equals 正文中,您可以将 observable 对象转换为 TestA 并比较其 name 属性,如下所示。

    在 TestA 类中。

    class TestA implements Observer {
        private name = '';
    
        equals = (item: Observer) => {
            if(item instanceof TestA){
              return this.name === (item as TestA).name
            }
            return false
        }
    
        notify = () => {}
    }
    

    【讨论】:

    • 这不合适,因为我可以这样做:new TestA().equals(new TestB) 并且我不会从 typescript 得到错误
    • 你能解释一下什么不适合吗?
    • 这很合适,因为当你执行 new TestA().equals(new TestB) 时它会返回 false
    • 我的意思是TS不会报告类型错误,但我想始终确保我将TestA与TestA和TestB与TestB进行比较
    • 在这种情况下,您必须更改接口和类的设计。以目前的设计,你无法做到这一点
    【解决方案2】:

    您是否考虑过使用polymorphic this 代替泛型?您的 ComparableObserver 将变为:

    interface Comparable {
        equals: (item: this) => boolean;
    }
    
    interface Observer extends Comparable {
        notify: () => void
    }
    

    意味着扩展ComparableX 类型的对象需要有一个equals() 方法,该方法采用X 类型的值。请注意,这意味着Comparable 在可替换性和继承性方面不像普通类型。一般来说,如果你有interface B extends A {...},那么你应该可以在任何需要A的地方使用B

    interface A {
        someMethod(x: A): void;
    }
    
    interface B extends A {
        someOtherMethod(x: B): void;
    }
    
    declare const b: B;
    const a: A = b; // okay
    

    但这不适用于Comparable

    declare const o: Observer;
    const c: Comparable = o; // error! equals is incompatible
    

    无论如何,Comparable 的这个定义将允许您按原样实现:

    class TestA implements Observer {
        private name = '';
    
        equals = (item: TestA) => {
            return this.name === item.name
        }
    
        notify = () => { }
    }
    
    class TestB implements Observer {
        private name = '';
    
        equals = (item: TestB) => {
            return this.name === item.name
        }
    
        notify = () => { }
    }
    

    但同样,如果您尝试将 TestATestB 视为 Observer,则会遇到问题:

    function takeObservers(o1: Observer, o2: Observer) {
        o1.equals(o2);    
    }
    takeObservers(new TestA()); // error
    

    因此,您可能会决定实际上不想以这种方式限制 equals()


    好的,希望对您有所帮助;祝你好运!

    Playground link to code

    【讨论】:

    • 多态 this - 这正是我需要的,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 2018-11-28
    • 1970-01-01
    • 2023-03-22
    • 2023-04-08
    • 1970-01-01
    相关资源
    最近更新 更多