Generic function using generic interface

Viewed 58

I would like to infer the return type of a generic function, but it seems like TypeScript doesn't have anything to help with it.

Given the following piece of code:

// Generic type for object key access
export type Indexable<T = unknown> = {[key:string]:T}

// My function that does something (usually retrieve data from an API and cast to T)
const myFOO = <T extends Indexable = Indexable>(input:Indexable)=>{
    return input as T // I know this is pointless but its for simplicity sake
}

// My objects type
type MyType = { a: string }

// Invoke the function with some data and MyType
const foo = myFOO<MyType>({'a':'b'})
/*
Return type is: MyType

This is correct as it should be
*/


type MyInferredReturnType=ReturnType<typeof myFOO>
/*
MyInferredReturnType is:
{
    [key: string]: unknown;
}

This is incorrect as I have no way to provide a generic to that function without invoking it
*/

So then I tried to create an interface that matches the function and use that for getting the return type:

interface myBAR<T extends Indexable = Indexable>{
    (input:Indexable):T
}

const myBAR: myBAR = <T extends Indexable = Indexable>(input: Indexable) => {
    return input as T // I know this is pointless but its for simplicity sake
}

const bar = myBAR<MyType>({ 'a': 'b' }) //Expected 0 type arguments, but got 1.

type MyInferredBARReturnType = ReturnType<myBAR<MyType>>
 /*
MyInferredBARReturnType is:
{
    [key: string]: unknown;
}
This is incorrect as I my provided type was not passed to the function
*/

Then I tried to add the generic in the interface to the function which fixes the Expected 0 type arguments, but got 1 error but ReturnType<myBAR<MyType>> still returns the wrong type

UPDATE:

There are two possible solutions to this issue but neither are perfect:

  1. Create an interface with the same name but do not use the interface for the function:

_

// Generic type for object key access
export type Indexable<T = unknown> = { [key: string]: T }

// My objects type
type MyType = { a: string }

interface myFOO<T extends Indexable = Indexable> {
    (input: Indexable): T
}

const myFOO = <T extends Indexable = Indexable>(input: Indexable) => {
    return input as T // I know this is pointless but its for simplicity sake
}


type MyInferredReturnType = ReturnType<myFOO<MyType>>
//MyInferredReturnType is MyType

const bar = myFOO<MyType>({ 'a': 'b' }) //Expected 0 type arguments, but got 

type t = typeof bar
// t is MyType

My issue with this one is the lack of connection between the function and the interface.

  1. Use Nadia Chibrikova's idea from the comments:

_

const myBAR: myFOO<MyType> = myFOO

type MyInferredBARReturnType = ReturnType<typeof myBAR>
//MyInferredBARReturnType is MyType

My issue with this one is I need to alias the function every time I want to change the generic type.

Is there a better way to achieve?

0 Answers
Related