TypeScript: handle generated union type for relationship

discord user avatar
alessiogr
last year
6

A relationship field has the type

string[] | MyCollection[]

which makes sense, as it could change depending on the depth which is used.



Now, how would you best handle the value of this field without too much run-time type checking? I'm using:


let relationshipValue = (
  await payload.findByID({
    collection: 'sites',
    id: docId,
    depth: 0,
  })
).relationship; // string[] | MyCollection[]

if (relationshipValue.length > 0 && typeof relationshipValue[0] === 'object') {
  relationshipValue = relationshipValue.map((doc) => doc.id);
}

relationshipValue = relationshipValue as string[];


However, this feels unsafe and beyond dirty. Any other ideas? Might as well cast it to

any

if I have to use type assertions (as

string[])

in the end

  • With depth 0 won't it always be string[]? Until we improve our internal typing to account for depth (if possible), I think you would be better off just casting right away



    let relationshipValue = (
      await payload.findByID({
        collection: 'sites',
        id: docId,
        depth: 0,
      })
    ).relationship as string[];
  • discord user avatar
    alessiogr
    last year
    With depth 0 won't it always be string[]

    Hm it would, but doing

    as string[]

    just feels dirty, it gives me more responsibility to know I can't just change the depth in the future 😅 Was hoping that there is some kind of way to let typescript infer the type, so I don't have to assert the type anymore

  • So one thing you will have to be weary of, what if you get docs back with depth: 1, but one of the docs was deleted (all that is left is the ID) or you dont have access to one of the docs (you will only get the ID).



    So with that in mind, I think the safest thing to do would be to always loop, check the type of the doc when looping and return the id or the doc.id

  • default discord avatar
    blupandamanlast year

    This is what I did in my project. Hard to reliably get back the Object rather than just the ID so I always type check manually to ensure I got back the right thing.

  • discord user avatar
    jmikrut
    last year

    yes you should always manually verify the data for sure

  • discord user avatar
    alessiogr
    last year

    ah didn't think of that either, that makes it even worse 😅



    I guess then this would really be the best/safest:


    let relationshipValue = (
      await payload.findByID({
        collection: 'sites',
        id: docId,
        depth: 0,
      })
    ).relationship;
    
    currentSummaries = currentSummaries.map((doc) => doc.id ?? doc) as string[];

    Although I really hate having to use

    as string[]

    Or I guess



    currentSummaries = currentSummaries.map((doc) => (doc.id as string) ?? (doc as string));

    is a bit nicer



    Mh found a nicer way!



    let relationshipValue = (
      await payload.findByID({
        collection: 'sites',
        id: docId,
        depth: 0,
      })
    ).relationship;
    
    relationshipValue = relationshipValue.map((doc: string | MyCollection) => {
      if (typeof doc === 'object') {
        return doc.id;
      } else {
        return doc;
      }
    });
Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.