Picci
Picci

Reputation: 17762

Functions with generics used as parameters in other functions

Let's say I define a type CoolType like this:

type CoolType<T> = {message: string, result: T} 

Then I define a CoolFunction type to describe a function that returns CoolType:

type CoolFunction = <T>() => CoolType<T>

CoolFunction is the type of parameter that a second function expects:

function superCoolFunction(coolFunction: CoolFunction) {
    return coolFunction()
}

Eventually, after all these definitions, I try to run some code like this:

const res = superCoolFunction(<string>() => {
    return {message: 'I am the message', result: 'I am the result'}
})

but, on <string>() => { of the above code I get an error from the compiler telling me that

'string' is declared but its value is never read.ts(6133) Argument of type '() => { message: string; result: string; }' is not assignable to parameter of type 'CoolFunction'. Call signature return types '{ message: string; result: string; }' and 'CoolType' are incompatible. The types of 'result' are incompatible between these types. Type 'string' is not assignable to type 'T'. 'string' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.ts(2345)

Any idea what I am doing wrong? Here's a stackblitz that reproduces the error.

Upvotes: 0

Views: 178

Answers (1)

jonrsharpe
jonrsharpe

Reputation: 122144

You seem to have generics in the wrong places. I think what you want is:

type CoolFunction<T> = () => CoolType<T>;

i.e. CoolFunctions also take a generic type. Then your higher-order function can propagate the generic:

function superCoolFunction<T>(coolFunction: CoolFunction<T>): CoolType<T> {
    return coolFunction();
}

Now the specific type can be inferred by the compiler:

superCoolFunction(() => ({ message: 'foo', result: 123 }));
// function superCoolFunction<number>(coolFunction: CoolFunction<number>): CoolType<number>

or supplied explicitly:

superCoolFunction<string>(() => ({ message: 'foo', result: 'bar' }));

Upvotes: 3

Related Questions