wavebeem
wavebeem

Reputation: 73

Why do type parameters disappear in TypeScript?

It seems like TypeScript is not capable of expressing a function which takes a generic function as a parameter and returns a generic function. Note the generic type <A> becoming {} in the following code sample with the function doubleton:

function compose<A, B, C>(
        g: (b: B) => C,
        f: (a: A) => B):  (a: A) => C {
    return a => g(f(a));
}

function singleton<A>(a: A): A[] { return [a]; }

// declare var doubleton: (a: {}) => {}[];
var doubleton = compose(singleton, singleton);

Oh no! We lost our type parameter A.

var x = 1; // number
var xs = singleton(x); // number[]
var xss = doubleton(x); // {}[]

And now we've seen the effects of doubleton's loss of genericity. Because of it, number became {}.

Is there some way to specify make compose preserve these type parameters, other than defining doubleton as follows?

function doubleton<A>(a: A) { return [[a]]; }

I know it seems trivial in this example, but I've run into more complex return-type cases (such as auto-curried functions) where it is non-trivial to reiterate yourself.

Upvotes: 3

Views: 410

Answers (1)

basarat
basarat

Reputation: 275947

The issue seems to be in the way type information of the form of function signatures interact with generic parameters. e.g. a simpler example (based on yours) that fails :

function mirror<A, B>(f: (a: A) => B)
    : (a: A) => B {
    return f;
}

function singleton<A>(a: A): A[] { return [a]; }

// (a:{})=>{}[]
var singletonMirror = mirror(singleton);

var x = 1;
var xs = singleton(x); // number[]
var xsM = singletonMirror(x); // {}[]

Will work if you do not ask the type system to infer A and B from f:

function mirror<T>(f: T)
    : T {
    return f;
}

function singleton<A>(a: A): A[] { return [a]; }

// okay
var singletonMirror = mirror(singleton);

var x = 1;
var xs = singleton(x); // number[]
var xsM = singletonMirror(x); // number[]

I would report it as an issue : https://github.com/microsoft/typescript/issues

A further simplification of the error:

function unity<A>(f: (a: A) => A)
    : (a: A) => A {
    return f;
}

function mirror<T>(a: T): T { return a; }

// (a:{})=>{}, should be (a:T)=>T
var unityMirror = unity(mirror);

Upvotes: 2

Related Questions