TypeScript: handle generated union type for relationship

discord user avatar
alessiogr
Payload Team
6 months ago
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

  • discord user avatar
    jarrod_not_jared
    Payload Team
    6 months ago

    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
    Payload Team
    6 months ago
    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

  • discord user avatar
    jarrod_not_jared
    Payload Team
    6 months ago

    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
    blupandaman
    6 months ago

    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
    Payload Team
    6 months ago

    yes you should always manually verify the data for sure

  • discord user avatar
    alessiogr
    Payload Team
    6 months ago

    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;
      }
    });
Open the post
Continue the discussion in Discord
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

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