Home > Blockchain >  Can a class implementing an interface include fields that are missing from the parent interface?
Can a class implementing an interface include fields that are missing from the parent interface?

Time:10-07

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.

  • Related