nestjs/nest

TS2416 & TS2322 errors related to the built-in FileValidator implementations

scur-iolus opened this issue ยท 8 comments

Did you read the migration guide?

  • I have read the whole migration guide

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Potential Commit/PR that introduced the regression

No response

NestJS version

9.4.3 -> 10.0.0

Describe the regression

TS errors after upgrading to v10.0.0. I'm not sure if this is a regression or if the documentation hasn't been updated yet. In any case, there seems to be a breaking change which isn't clearly reported. The issue stems from a short block of code very similar to the one given in the documentation (see below). When trying to build my application (yarn run build), I get these errors:

node_modules/@nestjs/common/pipes/file/file-type.validator.d.ts:19:5 - error TS2416: Property 'isValid' in type 'FileTypeValidator' is not assignable to the same property in base type 'FileValidator<FileTypeValidatorOptions>'.
  Type '<TFile extends IFile = any>(file: TFile) => boolean' is not assignable to type '<TFile extends IFile = any>(file?: TFile | undefined) => boolean | Promise<boolean>'.
    Types of parameters 'file' and 'file' are incompatible.
      Type 'TFile | undefined' is not assignable to type 'IFile'.
        Type 'undefined' is not assignable to type 'IFile'.

19     isValid<TFile extends IFile = any>(file: TFile): boolean;
       ~~~~~~~
node_modules/@nestjs/common/pipes/file/max-file-size.validator.d.ts:16:5 - error TS2416: Property 'isValid' in type 'MaxFileSizeValidator' is not assignable to the same property in base type 'FileValidator<MaxFileSizeValidatorOptions>'.
  Type '<TFile extends IFile = any>(file: TFile) => boolean' is not assignable to type '<TFile extends IFile = any>(file?: TFile | undefined) => boolean | Promise<boolean>'.
    Types of parameters 'file' and 'file' are incompatible.
      Type 'TFile | undefined' is not assignable to type 'IFile'.
        Type 'undefined' is not assignable to type 'IFile'.

16     isValid<TFile extends IFile = any>(file: TFile): boolean;
       ~~~~~~~
src/MY_PATH.controller.ts:44:11 - error TS2322: Type 'MaxFileSizeValidator' is not assignable to type 'FileValidator<Record<string, any>>'.
  Types of property 'isValid' are incompatible.
    Type '<TFile extends IFile = any>(file: TFile) => boolean' is not assignable to type '<TFile extends IFile = any>(file?: TFile | undefined) => boolean | Promise<boolean>'.

44           new MaxFileSizeValidator({ maxSize: MAX_FILE_SIZE }),
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/MY_PATH.controller.ts:45:11 - error TS2322: Type 'FileTypeValidator' is not assignable to type 'FileValidator<Record<string, any>>'.
  Types of property 'isValid' are incompatible.
    Type '<TFile extends IFile = any>(file: TFile) => boolean' is not assignable to type '<TFile extends IFile = any>(file?: TFile | undefined) => boolean | Promise<boolean>'.

45           new FileTypeValidator({ fileType: VALID_FILE_TYPES }),
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Everything works smoothly with the previous version of NestJS (yarn upgrade @nestjs/common@^9.4). I've checked the migration guide and haven't noticed any reference to the FileValidator.

Minimum reproduction code

See here

Input code

@UploadedFile(
  new ParseFilePipe({
    validators: [
      new MaxFileSizeValidator({ maxSize: 1000 }),
      new FileTypeValidator({ fileType: 'image/jpeg' }),
    ],
  }),
)
file: Express.Multer.File,

This piece of code is directly extracted from the documentation.

Expected behavior

No TS error :)

Other

No response

Please provide a minimum reproduction repository. You can start from this minimal project.

why reproductions are required

Here it is.

Side note, you need to turn on these settings in your tsconfig file:

    "strict": true,
    "skipLibCheck": false,

fixed in #11822

Published as v10.0.1

is this issue fixed cause I m currently on version 10.0.1 and the issue persists.

@sumann7916 this issue is not present in the latest version (10.0.5)

The issue still remains for me. This is the error I get now, with v10.0.5:

Property 'isValid' in type 'FileExtensionValidator' is not assignable to the same property in base type 'FileValidator<{ allowedExtensions: string[]; }>'.
  Type '(file?: File) => boolean | Promise<boolean>' is not assignable to type '<TFile extends IFile = any>(file?: TFile) => boolean | Promise<boolean>'.
    Types of parameters 'file' and 'file' are incompatible.
      Type 'TFile' is not assignable to type 'File'.
        Type 'IFile' is missing the following properties from type 'File': fieldname, originalname, encoding, stream, and 4 more.

  isValid(file?: Express.Multer.File): boolean | Promise<boolean> {

for this class:

export class FileExtensionValidator extends FileValidator<{
  allowedExtensions: string[]
}> {
  isValid(file?: Express.Multer.File): boolean | Promise<boolean> {
    return this.validationOptions.allowedExtensions.includes(extname(file.originalname))
  }
}

And I don't understand this error. Express.Multer.File implements the IFile interface, and <TFile extends IFile = any> means that TFile (which is Express.Multer.File in my case) has to implement IFile, right? But from the error message, it seams that IFile is supposed to implement TFile? Apologies if I don't understand fully how generic classes work in Typescript

Probably due to the fact typescript does not know that. I think creating a new type which implements IFile will probably work.