javascript - 在 TypeScript 中如何声明子类方法参数以更具体(无实现)?
例如,我可以在 TypeScript 中做以下事情吗?
我只是想在子类中缩小输入类型,以便更好地获得 IDE 的自动补全。我不想在里面像 super.foo(a) 那样编写实现。
(实际上,我正在继承 Node 的 EventEmitter,并且想缩小 on 和 emit 的 eventName 类型)
class Base {
foo (a: string){
// Do many things
}
}
class Child {
// I want to declare that this foo method can only accept these strings, and reuse the Base class's implementation
declare foo (a: 'AAA'|'BBB');
}
我知道有一种仅类型的字段声明,通过在类字段前添加declare,可以仅为继承的字段重新声明一个更准确的类型,这非常方便。
所以我想知道是否有办法对继承的方法做同样的事情。
答案#1
您目前无法在方法上使用 declare 修饰符。对此,microsoft/TypeScript#38008 有一个未决功能请求,但目前它不是语言的一部分。这意味着您需要通过重新实现覆盖方法来解决这个问题:
class Child extends Base {
foo(a: 'AAA' | 'BBB') {
super.foo(a);
}
}
或者通过将方法更改为函数值属性:
class Base {
foo = (a: string) => {
// Do many things
}
}
class Child extends Base {
declare foo: (a: 'AAA' | 'BBB') => void;
// ~~~ <-- error with --strictFunctionTypes
}
当然,你会看到,如果启用了 --strictFunctionTypes 编译器选项(属于 --strict 编译器选项套件的一部分),你会收到一个错误。子类假设 foo() 的参数比其父类期望的参数 更具体 是不安全的。这违反了参数类型的 逆变性(参见 TypeScript 中方差、协变、逆变和双变的区别),如果不小心,这可能会带来麻烦:
class Whoops extends Child {
foo(k: 'AAA' | 'BBB') {
({ AAA: 1, BBB: 2 })[k].toFixed(1);
}
}
function acceptBase(base: Base) { base.foo("oops") };
acceptBase(new Whoops()); // RUNTIME ERROR
假设你会小心。
目前支持这种做法的唯一方法是让 Base 在 foo() 的参数中成为泛型,然后为你的子类指定类型参数:
class Base<A extends string = string> {
foo(a: A) {
// Do many things
}
}
class Child extends Base<"AAA" | "BBB">{ }
代码的 Playground 链接
