0

How to get a generic type work with function variables? Following example doesn't work, but the idea is to have a generic function type.

type Request<T> = (input: RequestInfo, init: RequestInit) => Promise<T>
export const request: Request<T> = async <T>(input, init) => { // the second T is not recognized
  return fetch(input, init).then(res => {
    if (res.status < 300) {
      return res.json()
    }
    return res.json().then(Promise.reject)
  })
}
export const getRequest: Request<T> = <T>(input, init) => request<T>(input, { ...init, method: "GET" })

Shows error: Exported variable 'request' has or is using private name 'T'.

Mengo
  • 1,177
  • 1
  • 10
  • 25
  • https://stackoverflow.com/a/45576880/251311 – zerkms Mar 06 '21 at 01:26
  • @zerkms I tried that but didn't work. `export const request: Request = async (input, init) => { ... }`. Notice the type assignment is on the left not right of function assignment. – Mengo Mar 06 '21 at 01:40

1 Answers1

0

You can't. Generic parameters can only be defined on types, interfaces, functions, and classes. They can't be defined on arbitrary variable declarations.

Something you could do if you want to guarantee that all these functions match the "Request" structure is to make a no-op function whose only job is to check that the type works:

type MyRequest<T> = (input: RequestInfo, init: RequestInit) => Promise<T>;

function makeRequest<T extends MyRequest<unknown>>(request: T) { return request; }

const request = makeRequest(<T>(input: RequestInfo, init: RequestInit) => {
  return fetch(input, init).then(res => {
    if (res.status < 300) {
      return res.json()
    }
    return res.json().then(Promise.reject)
  }) as Promise<T>
});

const getRequest = makeRequest(<T>(input: RequestInfo, init: RequestInit) => 
  request<T>(input, { ...init, method: "GET" }));

const badRequest = makeRequest(<T>(notInput: number, notInit: Date) => 
  Promise.resolve()); // ERR because params don't match expectation
y2bd
  • 5,783
  • 1
  • 22
  • 25
  • Hi @y2bd, my understanding is we can assign type to variables, like `const a: number = 1` is legit, I don't know why it doesn't work for `const a: Request = (input, init) => {}`. Can this be read as we have a variable `a` as a function that satisfy `Request` type and accept a generic `T` type? – Mengo Mar 06 '21 at 07:04
  • I think I know what you mean now, seems it works for any predefined type like `const a: Request` but not generic ones. – Mengo Mar 06 '21 at 07:10