I currently have the following setup:
enum EnumA {
A,
AYE
}
enum EnumB {
B,
BEE
}
type A = keyof typeof EnumA
type B = keyof typeof EnumB
type AB = A | B
interface IBase {
foo: (...ok: AB[]) => IBase
}
abstract class Base implements IBase {
public foo(...ok: AB[]): Base {
return this
}
}
class BaseA extends Base implements IBase {
public override foo(...ok: A[]): Base {
return super.foo(...ok)
}
}
class BaseB extends Base implements IBase {
public override foo(...ok: B[]): Base{
return super.foo(...ok)
}
}
const myA: BaseA = new BaseA()
I expect that overriding the type of "ok" in the subclasses of Base and implementation of IBase should work, however typescript complains:
Property 'foo' in type 'BaseA' is not assignable to the same property in base type 'IBase'. Type '(...ok: ("A" | "AYE")[]) => Base' is not assignable to type '(...ok: AB[]) => IBase'. Types of parameters 'ok' and 'ok' are incompatible. Type 'AB' is not assignable to type '"A" | "AYE"'. Type '"B"' is not assignable to type '"A" | "AYE"'.ts(2416)
Any ideas what is going wrong here? I'd like to call myA.foo()
with type declarations that represent the type A, being a subset of type AB.
Any help would be greatly appreciated.
CodePudding user response:
You are declaring an interface that expects A|B
as an argument to a method. Any class that implements that interface must respect the contract
. This means that passing either A
or B
must be acceptable. When you are narrowing the type you are actually violating the contract for either A
or B
and this is not ok. What you probably want are generics.
enum EnumA {
A,
AYE
}
enum EnumB {
B,
BEE
}
type A = keyof typeof EnumA
type B = keyof typeof EnumB
type AB = A | B
interface IBase <T> {
foo: (ok: T) => IBase<T>
}
abstract class Base <T> implements IBase<T> {
public foo(...ok: T[]): Base<T> {
return this
}
}
class BaseA extends Base<A> implements IBase<A> {
public override foo(...ok: A[]): Base<A> {
return super.foo(...ok)
}
}
class BaseB extends Base<B> implements IBase<B> {
public override foo(...ok: B[]): Base<B>{
return super.foo(...ok)
}
}
const myA: BaseA = new BaseA()
Here's a playground link