Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make param type of BlobApi.getUrl() less strict? #483

Open
achou11 opened this issue Feb 19, 2024 · 4 comments
Open

Make param type of BlobApi.getUrl() less strict? #483

achou11 opened this issue Feb 19, 2024 · 4 comments

Comments

@achou11
Copy link
Member

achou11 commented Feb 19, 2024

Description

Currently doing some frontend work that uses the BlobApi to get the http url for a specified observation attachment. I'm having a difficult time appeasing TypeScript due to the getUrl(blobId) expecting a BlobId type, which is more precise (uses a discriminate union) and notably differs from an attachment type as described by Observation['attachments'][number] in mapeo schema.

The getUrl(blobId) works great if passing a value created by BlobApi.create() (as demonstrated in our tests), but given the type challenges when using the context of observation attachments, I'm wondering if we could update the param type to avoid convoluted typescript-specific code in the consuming application. Perhaps there's something I'm missing in terms of usage that is giving me problems with Typescript but my initial thought is that it would probably be easier to just update the param type (and maybe introduce runtime validation if really necessary)

@gmaclennan
Copy link
Member

What are the differences vs the attachment type? I thought it was only that the blobId has a variant property, which is necessary.

@achou11
Copy link
Member Author

achou11 commented Feb 19, 2024

What are the differences vs the attachment type? I thought it was only that the blobId has a variant property, which is necessary.

Yeah that's the primary difference in terms of defined fields, but I think there's something about how BlobId is defined that may be giving me some trouble? Given the following example:

export function someFunction(
  attachment: Observation['attachments'][number],
  // Also tried simplifying this to just 'original' | 'preview' | 'thumbnail'
  variant: BlobVariant<
    // TODO: Ideally derive this from `attachment` param or something that looks simpler...
    Exclude<Observation['attachments'][number]['type'], 'UNRECOGNIZED'>
  >,
) {
  return project.$blobs.getUrl({
      driveId: attachment.driveDiscoveryId,
      name: attachment.name,
      type: attachment.type,
      variant,
  })
}

I'm getting the following error:

Argument of type '{ driveId: string; name: string; type: "photo" | "video" | "audio"; variant: BlobVariant<"photo" | "video" | "audio">; }' is not assignable to parameter of type 'BlobId'.
  Types of property 'type' are incompatible.
    Type '"photo" | "video" | "audio"' is not assignable to type '"photo"'.
      Type '"video"' is not assignable to type '"photo"'.ts(2345)

Wish I could provide a TS playground link but importing the alpha version of mapeo schema doesn't seem feasible.

UPDATE: Seems like the main complaint is about using attachment.type for the type. If I provide an explicit value for it then the error goes away:

      return project.$blobs.getUrl({
        driveId: attachment.driveDiscoveryId,
        name: attachment.name,
        type: 'photo', // works with 'video' and 'audio' too
        variant,
      });

@gmaclennan
Copy link
Member

Yeah it's because each type has different variants available, so the type is strict to stop you requesting a variant that does not exist for the given type.

@achou11
Copy link
Member Author

achou11 commented Feb 19, 2024

Yeah it's because each type has different variants available, so the type is strict to stop you requesting a variant that does not exist for the given type.

Yeah the reasoning makes sense - is the only solution to do some (somewhat tedious) runtime checks before passing the arguments?

UPDATE: Not as tedious as I thought but definitely looks a little funny:

      switch (attachment.type) {
        case 'UNRECOGNIZED': {
          throw new Error('Cannot get URL for unrecognized attachment type');
        }
        case 'video':
        case 'audio': {
          if (variant !== 'original') {
            throw new Error('Cannot get URL of attachment for variant');
          }

          return project.$blobs.getUrl({
            driveId: attachment.driveDiscoveryId,
            name: attachment.name,
            type: attachment.type,
            variant,
          });
        }
        case 'photo': {
          return project.$blobs.getUrl({
            driveId: attachment.driveDiscoveryId,
            name: attachment.name,
            type: attachment.type,
            variant,
          });
        }
      }

UPDATE: What would be more ideal is to make sure that the variant param I'm defining is valid given the attachment param's type. Not sure how I'd go about that (although I'm guessing some incantations of type params are needed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants