I have a HATEOAS API that gives me structures based on my request. At the heart of it, it could be a single entity or an array of entities.
// single entity
{
links: [{ ... }],
data: {
links: [{ ... }],
data: {
id: 1,
title: "example entity"
}
}
}
// array of entities
{
links: [{ ... }],
data: [{
links: [{ ... }],
data: {
id: 1,
title: "example entity"
}
}, {
links: [{ ... }],
data: {
id: 2,
title: "another entity"
}]
}
My generic types for all responses are as follows
type Link = {
href: string;
ref: string;
type: string;
}
type EntityResponse<T> = { links: Link[], data: T };
type Response<T, Type extends [] | undefined> = {
links: Link[];
data: Type extends []
? EntityResponse<T>[]
: EntityResponse<T>;
}
Ideally I would be able to type the data using the entities type
Response<Product>
// or
Response<Product[]>
But as each of the entities is interpolated with a links
object it made it much trickier so I came up with the above.
So that if I wanted to define an array type response I would type it as follows
Response<Product, []>
For a single entity, I would type it
Response<Product>
I have a suspicion that I could remove the second type used conditionally but I’m unsure how I would achieve it given that I need to add the links
key/value pair into each individual entity and I don’t want to add this to the entity type. Can anyone point me in the right direction?
>Solution :
If you use a conditional type that infers the potential array elements, you will be to able use Response<Product>
and Response<Product[]>
to define your response types:
type Response<T> = {
links: Link[];
data: T extends (infer E)[]
? EntityResponse<E>[]
: EntityResponse<T>;
}