The Sharp Promise<Buffer>[] lacks some essential properties compared to the type Promise<File | File[]>: specifically, then, catch, finally, and [Symbol.toStringTag]

I wrote a script to verify and convert images as they pass through. Utilizing resources from nestjs, magic-bytes.js, and Sharp. However, I encountered the following error:

Type 'Promise<Buffer>[]' is missing the following properties from type 'Promise<File | File[]>': then, catch, finally, [Symbol.toStringTag]ts(2739)

Any assistance in resolving this issue would be greatly appreciated.

import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from "@nestjs/common";
import { filetypemime } from "magic-bytes.js";
import * as sharp from "sharp";

@Injectable()
export class ParseFile implements PipeTransform {
  async transform(
    incomingFiles: Express.Multer.File | Express.Multer.File[],
    metadata: ArgumentMetadata,
  ): Promise<Express.Multer.File | Express.Multer.File[]> {
    const files = Array.isArray(incomingFiles) ? incomingFiles : [incomingFiles];

    const bytes = files.map((file) => new Uint8Array(file.buffer));

    const fileMimetype = filetypemime(bytes);
    if (fileMimetype) {
      console.log(`File type is ${fileMimetype}`);
    }

    if (incomingFiles === undefined || incomingFiles === null) {
      throw new BadRequestException("Validation failed (file expected)");
    }

    if (Array.isArray(incomingFiles) && incomingFiles.length === 0) {
      throw new BadRequestException("Validation failed (files expected)");
    }

    const compressedFiles: Promise<Express.Multer.File | Express.Multer.File[]> = files.map(
      async (file) => await sharp(file.buffer).resize(320, 240).toFormat("webp").toBuffer(),
    );

    return Array.isArray(incomingFiles) ? compressedFiles : compressedFiles;
  }
}

I attempted to remove the type from compressedFiles, but then encountered a different error:

Type 'Promise<Buffer>[]' is not assignable to type 'File | File[]'

Answer №1

Buffer differs from an Express.Multer.File. Your compressedFiles constant is of type Buffer[] due to the files.map function. It seems like what you are trying to accomplish is something along the lines of

const compressedFiles: Promise<Express.Multer.File | Express.Multer.File[]> = await Promise.all(files.map(
  (file) => ({ 
    ...file,
    buffer: sharp(file.buffer).resize(320, 240).toFormat("webp").toBuffer()
  }),
));

Keep in mind that you cannot use async directly inside an Array.prototype.map method. If async functionality is required, it should be wrapped within Promise.all as demonstrated above.

Answer №2

This method has proven to be the most effective for me. I truly appreciate the guidance and support that led me to this insightful answer.

    import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from "@nestjs/common";
    import { filetypemime } from "magic-bytes.js";
    import * as sharp from "sharp";
    import { Readable } from "stream";
    import { randomUUID } from "crypto";
    
    @Injectable()
    export class ParseFile implements PipeTransform {
      async transform(
        incomingFiles: Express.Multer.File | Express.Multer.File[],
        metadata: ArgumentMetadata,
      ): Promise<Express.Multer.File | Express.Multer.File[]> {
        const files = Array.isArray(incomingFiles) ? incomingFiles : [incomingFiles];
    
        const bytes = files.map((file) => new Uint8Array(file.buffer));
    
        const mimeTypes = bytes.map((byte) => filetypemime(byte as any));
        if (mimeTypes.every((type) => type.includes("image"))) {
          throw new BadRequestException(
            `Validation failed (file should be an image), mimetype: ${mimeTypes}`,
          );
        }
    
        if (incomingFiles === undefined || incomingFiles === null) {
          throw new BadRequestException("Validation failed (file expected)");
        }
    
        if (Array.isArray(incomingFiles) && incomingFiles.length === 0) {
          throw new BadRequestException("Validation failed (files expected)");
        }
    
        const compressedFiles = await Promise.all(
          files.map(async (file) => {
            const buffer = await sharp(file.buffer).resize(320, 240).toFormat("webp").toBuffer();
            const newFile: Express.Multer.File = {
              fieldname: file.fieldname,
              originalname: `${randomUUID()}.webp`,
              encoding: file.encoding,
              mimetype: "image/webp",
              buffer: buffer,
              size: buffer.length,
              destination: "",
              stream: new Readable(),
              filename: "",
              path: "",
            };
            console.log(newFile);
            return newFile;
          }),
        );
        return Array.isArray(incomingFiles) ? compressedFiles : compressedFiles[0];
      }
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

After upgrading to version 8 of the Firebase JS SDK, the "firestore" module (imported as "firebase") could not be located within the "firebase" package

After upgrading the firebase JS SDK from v7 to v8.0.0, I changed my import of firebase as shown below. import * as firebase from 'firebase'; However, attempting to access certain properties resulted in an error message: firebase.firestore.FieldV ...

ExitDecorator in TypeScript

Introduction: In my current setup, I have an object called `Item` that consists of an array of `Group(s)`, with each group containing an array of `User(s)`. The `Item` object exposes various APIs such as `addUser`, `removeUser`, `addGroup`, `removeGroup`, ...

Aggregate and consolidate data based on multiple criteria while ensuring data integrity and maintaining type compliance

In search of a solution, I aim to organize an array of objects by a specified number of keys and calculate the sum of values of another set of keys. For instance, consider the following array: const arr = [ { type: "triangle", color: "green", available ...

The type 'Observable<HttpEvent<DeviceList>>' cannot be assigned to the type 'Observable<DeviceList>'

// FUNCTION TO RETRIEVE DEVICE LIST fetchDeviceList(): Observable < DeviceList > { this.setToken(); return this.http.get<DeviceList>(this.api_url + '/devices', this.httpOptions1) .retry(2); } I am facing a challenge in this p ...

Issue with Angular 5 EventEmitter causing child to parent component emission to result in undefined output

I've been trying to pass a string from a child component to its parent component. Child Component: //imports... @Component({ selector: 'child', templateUrl: './child.component.html', styleUrls: ['./child.c ...

How can you determine the number of times a particular digit appears around a specific position in a TypeScript array

(Utilizing Typescript for assistance) I am looking to determine the number of occurrences of the digit 2 surrounding a specific position within an array. The function takes in the position coordinates as parameters - param 1 for row and param 2 for column. ...

Retrieve an enumeration from a value within an enumeration

In my coding project, I have an enum called Animals and I've been working on a function that should return the value as an enum if it is valid. enum Animals { WOLF = 'wolf', BADGER = 'badger', CAT = 'cat', } cons ...

I'm curious about how to link a JSON field using dot notation in Angular 12 HTML

Does anyone know how to bind a JSON field using dot paths in Angular 12 HTML? For example: //Angular data: any = { name: 'x1', address: { city: 'xyz' } }; field: any = 'address.city'; //Html <input [(ngModel)]="data[ ...

How can TypeScript be effectively utilized with global packages?

Utilizing the global package to incorporate certain enzyme methods in test files without the need for importing: import { configure, shallow, render, mount } from 'enzyme'; ..... global.shallow = shallow; global.render = render; global.mount = ...

What is the process for integrating ng-bootstrap into an Angular 5 project?

Has anyone encountered issues loading ng-bootstrap in their Angular project? I'm experiencing difficulties and would appreciate any insights. Thank you for your help! This is my app.module.ts file: import { BrowserModule } from '@angular/platf ...

Is it necessary to use useCallback when executing a function from a child component?

Consideration should be given to using useCallback when ensuring referential equality during parent component renders. However, it's unclear if this is necessary in a scenario where the parent is dealing with a child function. import { ReactNode, useC ...

Eliminating the nested API call within a loop

After making an API call to retrieve a set of data such as a list of users, I noticed that I am implementing a for loop and within it, I am making another API call to obtain each user's profile details based on their ID. I understand that this approac ...

Remove Image Upload feature in antDesign and remove item from interface

I am currently working on a project that involves multiple interfaces. One of these interfaces is specifically designed for uploading images. However, I encountered a problem with the deletion icon functionality. Whenever the icon is clicked, a modal is su ...

Decorator in React that automatically sets the display name to match the class name

Is there a way to create a decorator that will automatically set the static property displayName of the decorated class to the name of the class? Example usage would be: @NamedComponent class Component extends React.Component { \* ... *\ } ...

The filter pipe in Angular 7 is not functioning properly

Upon page loading and API call initiation, I am encountering an issue with the ngFor loop not displaying all the values. However, when I manually input a search query in the search box for filtering, the functionality works flawlessly. My goal is for all v ...

Why is NestJs having trouble resolving dependencies?

Recently delving into NestJs, I followed the configuration instructions outlined in https://docs.nestjs.com/techniques/database, but I am struggling to identify the issue within my code. Error: Nest cannot resolve dependencies of the AdminRepository ...

How to pass a String Array to a String literal in JavaScript

I need to pass an array of string values to a string literal in the following way Code : var arr = ['1','2556','3','4','5']; ... ... var output = ` <scr`+`ipt> window.stringArray = [`+ arr +`] & ...

Nested self-referencing in Typescript involves a structure where

Please note that the code below has been simplified to highlight a specific issue. The explanation before the code may be lengthy, but it is necessary for clarity. Imagine I have a Foo class that represents a complex object. interface Config { bars:{ ...

What is the best approach for determining the most effective method for invoking a handler function in React?

As a newcomer to React, I am navigating through the various ways to define callback functions. // Approach 1 private handleInputChange = (event) => { this.setState({name: event.target.value}); } // Approach 2 private handleInputChange(event){ t ...

Creating an Angular form group that includes dynamic form controls with custom form control names

Seeking to implement a formGroup that dynamically adjusts based on JSON data like this: const LIMITS: Limit[] = [ { id: 'limit1', value: 1000, disabled: false }, { id: 'limit2', value: 500, disabled: tru ...