Reputation: 20621
I've defined the following interface type:
interface Input<TOutput> { }
And the following extension of that interface type:
interface ExampleInput extends Input<ExampleOutput> { }
interface ExampleOutput { }
I've also defined the following "service" interface:
interface Service {
invoke<TInput extends Input<TOutput>, TOutput>(input: TInput): Observable<TOutput>
}
However, when I try to call it with an instance of ExampleInput
, it fails:
function example(service: Service) {
service.invoke({} as ExampleInput).subscribe((output: ExampleOutput) => {
console.log(output);
});
}
error TS2769: No overload matches this call.
Overload 1 of 3, '(observer?: Partial<Observer<unknown>> | undefined): Subscription', gave the following error.
Type '(output: ExampleOutput) => void' has no properties in common with type 'Partial<Observer<unknown>>'.
Overload 2 of 3, '(next: (value: unknown) => void): Subscription', gave the following error.
Argument of type '(output: ExampleOutput) => void' is not assignable to parameter of type '(value: unknown) => void'.
Types of parameters 'output' and 'value' are incompatible.
Type 'unknown' is not assignable to type 'ExampleOutput'.
Overload 3 of 3, '(next?: ((value: unknown) => void) | null | undefined, error?: ((error: any) => void) | null | undefined, complete?: (() => void) | null | undefined): Subscription', gave the following error.
Argument of type '(output: ExampleOutput) => void' is not assignable to parameter of type '(value: unknown) => void'.
Types of parameters 'output' and 'value' are incompatible.
Type 'unknown' is not assignable to type 'ExampleOutput'.
185 service.invoke({} as ExampleInput).subscribe((output: ExampleOutput) => {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Why is the return type of the Observable
's subscribe
callback either unknown
or void
, when I'd expect it to be ExampleOutput
?
Elaborating with a different language example, in JVM Kotlin, the following compiles and behaves as expected (with the appropriate implementaions to actually run)
fun interface Subscriber<TOutput>
{
fun subscribe(callback: (output: TOutput) -> Unit): Unit
}
interface Input<TOutput>
interface ExampleInput : Input<ExampleOutput>
interface ExampleOutput
interface Service
{
fun <TInput : Input<TOutput>, TOutput> invoke(input: TInput): Subscriber<TOutput>
}
fun example(service: Service)
{
service.invoke(object : ExampleInput { }).subscribe { output: ExampleOutput ->
println(output)
}
}
Upvotes: 1
Views: 175
Reputation: 32148
Currently with you definition
interface Service {
invoke<TInput extends Input<TOutput>, TOutput>(input: TInput): Observable<TOutput>
}
it's defining a method that accepts an argument that has to have the properties of Input<TOutput>
and the returned type is unknown because you haven't passed value for it. To do so you can invoke it by
service.invoke<string, number>.subscribe()
Probably you'd want to describe your service interface as with generics in the service as probably there the type is known
interface Service<O> {
invoke(input: Input<O>): Observable<O>
}
function example(service: Service<ExampleOutput>) {
service.invoke({}).subscribe((output) => {
console.log(output);
});
}
Upvotes: 1