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;
}
}