Search code examples
typescriptnestjsbackendpipelinesharp

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


I have written a code that should verify and convert every image that passes through it. I made use from nestjs, magic-bytes.js and Sharp. But i get an error that says:

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

Can someone help me fix this?

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 have tried to remove the type by compressedFiles, but then i got another error that says:

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


Solution

  • I found that this works best for me. Thanks for the help, because i got a lot of inspiration from the answer that i got.

        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];
          }
        }