I can define and use a generic function like this:

const fetchData = <T>(): T[] => {
  const arr: T[] = []
  // if stuff push to arr
  return arr
}

const emptyStringArray = fetchData<string>();

However, in my actual scenario, I have a lot of params and would like to separate out the typings and function assignment.

I've attempted to write like this:

type IFetchData = <T>() => T[]

const fetchData2: IFetchData = () => {
  const arr: T[] = []
  // if stuff push to arr
  return arr
}

const emptyStringArray = fetchData2<string>();

However, now the function definition doesn't recognize the T as an available type.

Cannot find name 'T'.

I've tried a lot of different configurations on where to put the <T>, but nothing seems to work - any ideas?

Demo in TS Playground


Related Questions

First of all, this function:

const fetchData = <T,>(): T[] => {
    const arr: T[] = []
    arr.push(2) // error
    arr.push('str') // error

    return arr
}

is hard to use.

Since non of your arguments are not related to T, TS will not allow you to push any value to the arr. Of course, you can use type assertion as, but it is very unsafe:

const fetchData = <T,>(): T[] => {
    const arr: T[] = []
    arr.push('str' as any as T) // error

    return arr
}

const emptyStringArray = fetchData<number>(); // number[]
emptyStringArray[0].toExponential() // runtime error

Related question/answer, my article

The answer is easy and simple: it is impossible in this case to separate T from function definition without workarounds.

Here you have simplest way:

const fetchData = <T,>() => {
  const arr: T[] = []
  return arr
}

However, if you want to mutate your array inside fetchData, this function signature is not useful. This function is not allowed to do anything with arr. All you can do is to return arr without any mutations.

In order to mutate this list, you need create higher order function and during calling fetchData provide explicit generic argument:

type FetchData = <T>() => T[]
const fetchData: FetchData = () => []

const higherOrder = <T,>(elem: T) => {
  const arr = fetchData<T>();
  arr.push(elem)

  return arr
}



const test = higherOrder('str'); // ok, string[]
const test2 = higherOrder(42); // ok, number[]

Playground