Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is is possible to split a generic type?

Tags:

typescript

API endpoints that I call deliver data in the following shapes:

interface ArrayResponse<T> {
   data: Partial<T>[]
}
interface ObjectResponse<T> {
   data: Partial<T>
}

I've written a function that calls endpoints and returns responses:

function fetchOne<T>(path: string): ObjectResponse<T> {
  // HTTP call
}

function fetchMany<T>(path: string): ArrayResponse<T> {
  // Exact same HTTP logic as above
}

Ideally I want to have a single response type:

interface Response<T> {
  data: Partial<T> | Partial<T>[]
}

But I what I really want is to be able to have the above type to determine Partial or Partial[] based on the value passed for T.

So Response<T> would result in data: Partial<T> and Response<T>[] results in data: Partial<T>[].

I'm also open to other creative ways of achieving the same effect.

like image 242
fny Avatar asked May 23 '26 10:05

fny


1 Answers

It can be done. But regardless of how you set this up you would need to manually set the generic T when calling, like fetch<MyType>(path), in order to get a meaningful response type because the generic T cannot possibly be inferred from the path which is a string.

Try this:

function fetchEither<T>(path: string): T extends (infer U)[] ? ArrayResponse<U> : ObjectResponse<T> {   
}

With this setup, you would pass in MyType as T to get a single response or MyType[] as T for a multiple response. (note: this assumes that MyType itself would not be an array)

const array = fetchEither<MyType[]>(""); // has type ArrayResponse<MyType>
const object = fetchEither<MyType>(""); // has type ObjectResponse<MyType>

Typescript Playground Link

Given that T cannot be inferred, it might make more sense to just return a union type and determine the value at runtime as proposed by @Thatkookooguy.

like image 50
Linda Paiste Avatar answered Jun 02 '26 23:06

Linda Paiste



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!