我目前正在尝试将一些类型添加到一个非常依赖继承的库中。一般层次结构类似于:
BaseWidget --> TextBox --> ValidationTextBox
BaseWidget 提供了一个名为getObj(name)
的JS 函数映射到 getObj(name: string): any
在 TS 中并有效地在当前对象上查找名为 _get<name>
的函数, 执行它,并返回结果。
这些“属性”在各个类上公开,并在类之间继承,这样 ValidationTextBox 就可以访问 TextBox 上的所有属性。我想知道是否可以添加类似于我在下面尝试过的类型,而不必在每个类中重新定义重载。
interface BaseWidget {
getObj(name: string): any
}
interface TextBox extends BaseWidget {
getObj(name: "B"): string
}
interface ValidationTextBox extends TextBox {
getObj(name: "C"): boolean
// getObj(name: "B"): string; // Adding this would make it compile, but obviously not ideal in the least
// getObj(name: string): any // Adding this also compiles, but I lose type information for 'getObj("B")'
}
declare const obj: ValidationTextBox;
console.log(obj.getObj("B")); // Error: Argument of type '"B"' is not assignable to parameter of type '"C"'
当前解决方案的错误是 Interface 'ValidationTextBox' incorrectly extends interface 'TextBox'.
因为在 getObj(...)
中“B”不可分配给“C” .
感谢帮助!
最佳答案
可能有几种解决方案。最简单的方法是通过指定额外的重载但不使用类型查询重写它们来让编译器满意:
interface ValidationTextBox extends TextBox {
// The extra overload with C, and whatever overloads are in the base class (TextBox['getObj'])
getObj: ((name: "C") => boolean) & TextBox['getObj'];
}
另一种解决方案是使类型通用,以允许我们添加到 name
参数的类型,而无需实际覆盖方法:
interface BaseWidget<TName = string> {
getObj(name: TName): any
}
// TName can be used to add to the getName overload in derived interfaces
interface TextBox<TName = never> extends BaseWidget<TName | "B"> {
}
// TName can be used to add to the getName overload in derived interfaces
interface ValidationTextBox<TName = never> extends TextBox<TName | "C"> {
}
declare const obj: ValidationTextBox;
console.log(obj.getObj("B"));
console.log(obj.getObj("C"));
关于Typescript 继承并重载了函数的字符串文字参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51017009/