Home > Enterprise >  Why does TypeScript complaint about missing property in generic inheritance?
Why does TypeScript complaint about missing property in generic inheritance?

Time:12-05

Consider the following test case :

interface BaseFoo {}

interface FooAdapter {
  method<F extends BaseFoo>(foo:F):string;
}


interface ConcreteFoo extends BaseFoo {
  value:string;
}

class ConcreteFooAdapter implements FooAdapter {
  method(foo: ConcreteFoo): string {
    return foo.value;
  }
}

The only error is with the method signature, where TypeScript complaints that :

Property 'value' is missing in type 'BaseFoo' but required in type 'ConcreteFoo'.

Why would value be present in BaseFoo since the generic F is supposed to extend it?

But, more importantly, how to fix this so there is no error?

Edit

Here is an alternative solution I was trying to investigate, but with similar failure:

interface BarAdapter {
  method<F>(bar:F):string;
}

type Bar = {
  value:string;
}

class ConcreteBarAdapter implements BarAdapter {
  method(bar:Bar):string {
    return bar.value;
  }
}

It complaints that F is not assignable to type Bar, and I don't understand why.

CodePudding user response:

If your only criteria is that the parameter should extend BaseFoo, and the return value should be a string, you may not need generics at all, this would be enough:

interface BaseFoo { }

interface FooAdapter {
  method(foo: BaseFoo): string;
}

interface ConcreteFoo extends BaseFoo {
  value: string;
}

class ConcreteFooAdapter implements FooAdapter {
  method(foo: ConcreteFoo): string {
    return foo.value;
  }
}

This provide as strong typing as in your attempt with generics. TypeScript constraints method in the implementor to extend method(foo: BaseFoo): string.

However, if you need to be able to use the adapters as implementors of a specific method signature, then you'd have to add the generic parameter on the interface, and then provide the type explicitly when implementing it:

interface BaseFoo { }

interface FooAdapter<F extends BaseFoo>  {
  method(foo: F): string;
}


interface ConcreteFoo extends BaseFoo {
  value: string;
}

class ConcreteFooAdapter implements FooAdapter<ConcreteFoo> {
  method(foo: ConcreteFoo): string {
    return foo.value;
  }
}
  • Related