Working with the code below. I want to enforce the constraint that all classes implementing InterfaceParent
have a function called add
that accepts an InterfaceParent
(or an implementing class) and return an InterfaceParent
(or an implementing class). However, since InterfaceChild
has a new field, randomVariable
that is missing from the interface it implements, I get the following error:
Property 'add' in type 'InterfaceChild' is not assignable to the same property in base type 'InterfaceParent'.
Type '(n: InterfaceChild) => InterfaceChild' is not assignable to type '(n: InterfaceParent) => InterfaceParent'.
Types of parameters 'n' and 'n' are incompatible.
Property 'randomVariable' is missing in type 'InterfaceParent' but required in type 'InterfaceChild'.ts(2416)
InterfaceParentChild.ts(6, 3): 'randomVariable' is declared here.
What's going on here? The code I'm working on:
interface InterfaceParent {
add: (n: InterfaceParent) => InterfaceParent
}
class InterfaceChild implements InterfaceParent {
randomVariable: number = 1
add = (n: InterfaceChild): InterfaceChild => new InterfaceChild()
}
export default InterfaceChild
CodePudding user response:
The error message spells it out pretty clearly:
Type (n: InterfaceChild) => InterfaceChild
is not assignable to type (n: InterfaceParent) => InterfaceParent
.
Types of parameters 'n' and 'n' are incompatible.
Your class InterfaceChild
doesn't correctly implement InterfaceParent
because the add
function must accept any InterfaceChild
as it's argument. You cannot make your type constrains more strict on inputs in a class that implements an interface.
However, you can be more strict regarding the output type of the function, so the return type of InterfaceChild
is fine because all InterfaceChild
types will implement InterfaceParent
.
interface InterfaceParent {
add: (n: InterfaceParent) => InterfaceParent
}
class InterfaceChild implements InterfaceParent {
randomVariable: number = 1
add = (n: InterfaceParent): InterfaceChild => new InterfaceChild()
}
export default InterfaceChild
CodePudding user response:
As an alternative to Paul's excellent answer, you can use Generics to tell TypeScript which class your method will use in parameter:
interface InterfaceParent<T extends InterfaceParent<any>> {
add: (n: T) => T
}
class InterfaceChild implements InterfaceParent<InterfaceChild> {
randomVariable: number = 1
add = (n: InterfaceChild) => new InterfaceChild()
}
Here, I declare a generic T
which extends InterfaceParent
, and during the implementation, I declare that your function will use InterfaceChild
.