Reputation: 73
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
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