The if (file typeof UploadedFile[]) part will not work because typeof is a JS runtime check, and UploadedFile[] is a type. The concept of types does not really exist at runtime, therefore it's impossible to execute the statement.
But the first check for file being an array should actually be enough. By writing code that handles the type UploadedFile | UploadedFile[] you're basically trusting any variable that is assigned that type to have a value of that type at runtime. So if it's not an array, it must be a value of type UploadedFile:
if (Array.isArray(req.files.file)) {
// It must be an array of UploadedFile objects...
} else {
// It must be a single UploadedFile object...
}
The tedious part is that as long as a variable has a union type like this, you'd have to write constructs similar to if...else anywhere you want to perform operations on the variable (read it, transform it, or otherwise use it). Is there a cleaner way?
You could normalize the value of file to always be an array, and then always treat it as such
If req.files.file is an array, let myFiles be req.files.file. Otherwise let myFiles be an array containing 1 element which is req.files.file:
const myFiles: UploadedFile[] = Array.isArray(req.files.file)
? req.files.file
: [req.files.file];
Now consider having a function handleSingleFile that you must run for all files that came out of req.files.file. Instead of writing:
if (Array.isArray(req.files.file)) {
req.files.file.forEach((file) => handleSingleFile(file));
} else {
handleSingleFile(req.files.file);
}
...you know that myFiles will always be an array:
myFiles.forEach((file) => handleSingleFile(file));