What I am trying to achieve:我希望使用接收类型T的值并返回SAVE VALUE的方法saveChanges的BACIS ChangeListener.我还想有ChangeListenerWithModifier,覆盖ChangeListener类,并扩展saveChanges方法.在本例中,值类型为T,但它将不同的值类型传递给父saveChanges方法.

class ChangeListener<T, R = T> {
    changes: R;

    saveChanges(value: T): R {
        this.changes = value;
        return value;
    }
}

class ChangeListnerWithModifier<T, B> extends ChangeListener<B> {
    constructor(private modifier: (value: T) => B) {
        super();
    }

    saveChanges(value: T): B {
        return super.saveChanges(this.modifier(value));
    }
}

在我目前的设置中,我在ChangeListener saveChanges方法中收到错误

类型‘T’不可赋值给类型‘R’. "R"可以用与"T"无关的任意类型实例化.此类型参数可能需要扩展R约束.

我理解这个错误,但这正是我需要的.我的返回类型可能与T相同,但它可以是完全不同的类型,而不是扩展T.

还有一个错误,那就是ChangeListnerWithModifier个saveChanges方法

类型""ChangeListnerWithModifierT,B&>""中的属性""saveChanges""不能赋值给基本类型""ChangeListener&lt;B,B&>""中的同一属性."" 类型‘(Value:t)=&gt;B’不可分配给类型‘(Value:B)=&gt;B’. 参数‘Value’和‘Value’的类型不兼容. 类型‘B’不可赋值给类型‘T’. ‘t’可以用与‘B’无关的任意类型实例化.ts(2416)

我可以采用不同的方法,在ChangeListener个父类中使用单一类型

class ChangeListener<T> {
    changes: T;

    saveChanges(value: T): T {
        this.changes = value;
        return value;
    }
}

class ChangeListnerWithModifier<T, B> extends ChangeListener<B> {
    constructor(private modifier: (value: T) => B) {
        super();
    }

    saveChanges(value: T): B {
        return super.saveChanges(this.modifier(value));
    }
}

但是,扩展该类并使用不同的返回类型签名重写它的方法会出现问题.现在children类中的saveChanges给了我类型错误:

类型""ChangeListnerWithModifierT,B&>""中的属性""saveChanges""不能分配给基类型""ChangeListener""中的同一属性."" 类型‘(Value:t)=&gt;B’不可分配给类型‘(Value:B)=&gt;B’. 参数‘Value’和‘Value’的类型不兼容. 类型‘B’不可赋值给类型‘T’. ‘t’可以用与‘B’无关的任意类型实例化.ts(2416)

推荐答案

不能实现它的原因是因为它不是类型安全的.ChangeListener<T>必须有接受TsaveChanges()方法.如果是ChangeListnerWithModifier<U, T> extends ChangeListener<T>,则其saveChange()方法必须also接受T.如果没有,那么你就会冒着真正的风险,有人要ChangeListener<string>,你给他们ChangeListenerWithModifier<number, string>,然后拨打saveChange("xyz"),然后看着发生的某种疯狂的运行时问题:

function foo(x: ChangeListener<string>) {
   x.saveChanges("abc");
}
const m = new ChangeListnerWithModifier((value: number) => value.toFixed(1));

foo(m); // if this were acceptable, you'd get a runtime error

您可以try 推动这种不一致,但如果您继续try 使用继承来解决此问题,则不会解决问题.


如果你想获得类型安全,那么你需要以某种方式重构你正在做的事情.在这种情况下,一个标准的方法是支持composition over inheritance.不是ChangeListnerWithModifier being a ChangeListener,而是has a ChangeListener. 这可能看起来像:

class ChangeListnerWithModifier<U, T>{

    private innerListener: ChangeListener<T> = new ChangeListener<T>();

    constructor(private modifier: (value: U) => T) {
    }

    saveChanges(value: U): T {
        return this.innerListener.saveChanges(this.modifier(value));
    }
}

现在,没有压力试图迫使saveChanges()做两件不相容的事情.您可以定义一些ChangeListnerWithModifier<U, T>ChangeListener<T>都支持的接口,这取决于您的用例.构图当然有缺点,但这是一个常见的 Select .

Playground link to code

Typescript相关问答推荐

具有映射返回类型的通用设置实用程序

如何设置绝对路径和相对路径的类型?

尽管对象的类型已声明,但未解析的变量<;变量

FatalError:Error TS6046:';--模块分辨率';选项的参数必须是:'; node ';,'; node 16';,'; node

以Angular 执行其他组件的函数

保护函数调用,以便深度嵌套的对象具有必须与同级属性函数cargument的类型匹配的键

使用条件类型的类型保护

TypeScrip:使用Union ToInterval辅助对象,但保留子表达式

S,为什么我的T扩展未定义的条件在属性的上下文中不起作用?

打印脚本中正则函数和函数表达式的不同类型缩小行为

TaskListProps[]类型不可分配给TaskListProps类型

如何在本地存储中声明该类型?

编剧- Select 动态下拉选项

编剧- Select 下拉框

如何提取具有索引签名的类型中定义的键

如何使用 Angular 确定给定值是否与应用程序中特定单选按钮的值匹配?

递归地排除/省略两种类型之间的公共属性

如何判断路由或其嵌套路由是否处于活动状态?

redux-toolkit、createAsyncThunk 错误

如何在 ngFor 循环中以Angular 正确动态渲染组件