Question

There is a error in the code below with the lots of lines of text. When I change the Y parameter of the generic in the arrow marked line to the type such as number or string all is ok, no error after compilation

Question 1 - is it a compiler bug ? Question 2 - how to fix the error ?

class channel<S,Y>{

public merge(...channels:channel<any, Y>[]) {

    var ch = new channel<void, channel<any, Y>>(); // <---

    var result = ch.flatMap(x => x);

    return result;
}

public flatMap<R>(projector: (data: Y) => channel<any, R>): channel<Y, R> {
    return null;
}
}

expected type of result is channel<any, Y>, but the compiler infers something different

Error message:

Error   1   Supplied parameters do not match any signature of call target:
Call signatures of types '(x: channel<any, channel<any, Y>>) => channel<any, channel<any, Y>>' and 
                         '(data: channel<any, channel<any, Y>>) => channel<any, Y>' are incompatible:
    Types 'channel<any, channel<any, Y>>' and 'channel<any, Y>' originating in infinitely expanding type reference have incompatible type arguments.    

Update

public flatMap<R>(projector: (data: Y) => channel<any, R>): channel<any, R> {} // changed Y to any

public correct(...targets: channel<any, Y>[]) {
    var ch = new channel<void, channel<any, Number>>().named('merge');

    var result = ch.flatMap(x => x);


    return result;
}     

public incorrect(...targets: channel<any, Y>[]) {
    var ch = new channel<void, channel<any, Y>>().named('merge'); // changed Number to Y

    var result = ch.flatMap(x => x); // error


    return result;
}     

Some magic there. When I changed like that, I got (x:Number):Number => x . But when use Y, x is channel<any, channel<any,Y> >

Was it helpful?

Solution

expected type of result is channel<any, Y>

I don't see how you arrived at this conclusion. Following the definition of this class and function:

  1. The type of ch is channel<void, channel<any, Y>> (explicitly given)
    • ch#S = void
    • ch#Y = channel<any, Y>
  2. flatMap<R> returns channel<Y, R> when invoked on a a channel<S, Y> (explicitly given)
  3. For this invocation of ch.flatMap, Y = channel<any, Y> (from 1.b)
  4. The return type is therefore channel<channel<any, Y>, R> (substitute in Y from the definition in 2)

Anyway, because you have an infinitely expanding generic type (see TypeScript spec section 3.8.7), generic type inference is going to be necessarily limited (I believe the problem is actually undecidable). Your best bet in this situation is going to be to specify the type parameter manually, or give the compiler an extra hint by providing a type annotation for x.

OTHER TIPS

This may or may not be a bug with type inference. It's a complicated example so maybe there's a reason the generic type can't be inferred. You can help it out by specifying what R is when you call flatMap<R>()

var result = ch.flatMap<channel<any, Y>>(x => x);

or by fully qualifying the lambda

var result = ch.flatMap((x: channel<void, channel<any, Y>>): channel<void, channel<any, Y>> => {
    return x;
});

I think the first one looks a lot nicer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top