#Predict return type of `Array.includes`

1 messages · Page 1 of 1 (latest)

umbral bramble
#

I have a relatively complex Prisma query which I use quite often with minor variations as part of larger queries. To simplify usages of this query, I made a function which takes an array of things to select as a parameter and returns the query.

function currentMetadataSelect(select: ("title" | "description" | "thumbnailUrl" | "createdAt")[]) {
  return {
    createdAt: select.includes("createdAt"),
    proposedMetadata: {
      select: {
        metadata: {
          select: {
            title: select.includes("title"),
            thumbnail: select.includes("thumbnailUrl") ? { select: { url: true } } : false,
            description: select.includes("description")
          }
        }
      },
      ...
    }
  };
}

However, regardless of what I pass to the function, the return type always evaluates to

{
  createdAt: boolean,
  proposedMetadata: {
    select: {
      metadata: {
        select: {
          title: boolean,
          thumbnail: { select: { url: true } } | false,
          description: boolean
        }
      }
    },
    ...
  }
}
```Which of course makes sense. However, this means that the return type of my Prisma queries isn't at all specific, and Prisma's great typing is the main reason I use it!

So, I tried the below code
```ts
type MetadataBit = "title" | "description" | "thumbnailUrl" | "createdAt";

type MetadataSelect<T extends MetadataBit[]> = {
  createdAt: T[number] extends "createdAt" ? true : false;
  proposedMetadata: {
    select: {
      metadata: {
        select: {
          title: T[number] extends "title" ? true : false;
          thumbnail: T[number] extends "thumbnailUrl" ? { select: { url: true } } : false;
          description: T[number] extends "description" ? true : false;
        }
      }
    };
    ...
  }
}

export function currentMetadataSelect<T extends MetadataBit[]>(select: T): MetadataSelect<T> {
  return ... as MetadataSelect<T>;
}
#

However, T[number] extends X seems to check if all of T is X, rather than if T contains X, meaning this doesn't work for a select with more than 1 item. Is there something I could do instead?

light finch
#

T[number] extends X checks whether T[number] is assignable to X

#

Maybe you want X extends T[number] to see if X is in the union T[number] ?

#

I haven't tried to understand the whole thing here, so can't verify that it's correct in general

umbral bramble
#

That worked, thank you so much!

#

!resolved

lime sphinx
#

btw you can't do this in general

#

types are broader than values

#

you can't guarantee that "a" is in or not in ["a" | "b"] or ("a" | "b")[] or string[]

umbral bramble
#

Yes, but you can with ["a", "b"] which is what is actually being passed as the generic

lime sphinx
#

you can't guarantee that a tuple with non-union members is passed through constraints though; you may want a validation type for that

#

also btw for generics constrained to arrays, you should use readonly T[] instead of T[], it's broader

lime sphinx