Skip to main content

isFile

Determines whether a value is a File object with enhanced type safety. Provides reliable File detection with environment compatibility, identifying File objects used in web applications for file handling. File objects extend Blob functionality with additional metadata like name and last modified time. Returns false in environments where File API is not available.

Signature

const isFile: (value: unknown) => value is File

Parameters

NameTypeDescription
value-Value to test for File type

Returns

Type-safe boolean indicating whether the value is a File object

Examples

Basic File detection

import { isFile } from '@winglet/common-utils';

// True cases - File instances (in browser environment)
if (typeof File !== 'undefined') {
const file1 = new File(['content'], 'test.txt', { type: 'text/plain' });
const file2 = new File(['<h1>Hello</h1>'], 'test.html', { type: 'text/html' });

console.log(isFile(file1)); // true
console.log(isFile(file2)); // true
}

// False cases - not File objects
console.log(isFile(new Blob(['content']))); // false (Blob, not File)
console.log(isFile('filename.txt')); // false (string)
console.log(isFile({ name: 'file.txt', size: 100 })); // false (file-like object)
console.log(isFile(null)); // false
console.log(isFile(undefined)); // false

// Environment without File API support (e.g., older Node.js)
console.log(isFile(anything)); // always false

File upload handling

interface FileUploadHandler {
handleFileUpload(files: unknown[]): Promise<UploadResult[]>;
}

interface UploadResult {
success: boolean;
filename?: string;
size?: number;
error?: string;
}

class WebFileUploadHandler implements FileUploadHandler {
async handleFileUpload(files: unknown[]): Promise<UploadResult[]> {
const results: UploadResult[] = [];

for (const file of files) {
if (!isFile(file)) {
results.push({
success: false,
error: 'Invalid file object'
});
continue;
}

// TypeScript knows file is File
try {
const result = await this.processFile(file);
results.push({
success: true,
filename: file.name,
size: file.size
});
} catch (error) {
results.push({
success: false,
filename: file.name,
error: error.message
});
}
}

return results;
}

private async processFile(file: File): Promise<void> {
// Validate file
if (file.size > 10 * 1024 * 1024) { // 10MB limit
throw new Error('File too large');
}

const allowedTypes = ['image/jpeg', 'image/png', 'text/plain', 'application/pdf'];
if (!allowedTypes.includes(file.type)) {
throw new Error('File type not allowed');
}

// Process file content
const content = await file.text();
console.log(`Processing ${file.name}: ${content.length} characters`);
}
}

File input validation

interface FileValidationRule {
name: string;
validate: (file: File) => boolean;
errorMessage: string;
}

class FileValidator {
private rules: FileValidationRule[] = [
{
name: 'size',
validate: (file) => file.size <= 5 * 1024 * 1024, // 5MB
errorMessage: 'File size must be less than 5MB'
},
{
name: 'type',
validate: (file) => file.type.startsWith('image/'),
errorMessage: 'Only image files are allowed'
},
{
name: 'name',
validate: (file) => file.name.length > 0 && file.name.length <= 255,
errorMessage: 'Filename must be between 1 and 255 characters'
}
];

validateFile(file: unknown): { valid: boolean; errors: string[] } {
if (!isFile(file)) {
return {
valid: false,
errors: ['Invalid file object']
};
}

const errors: string[] = [];

for (const rule of this.rules) {
if (!rule.validate(file)) {
errors.push(rule.errorMessage);
}
}

return {
valid: errors.length === 0,
errors
};
}

validateFiles(files: unknown[]): {
validFiles: File[];
invalidFiles: Array<{ file: unknown; errors: string[] }>
} {
const validFiles: File[] = [];
const invalidFiles: Array<{ file: unknown; errors: string[] }> = [];

for (const file of files) {
const validation = this.validateFile(file);

if (validation.valid && isFile(file)) {
validFiles.push(file);
} else {
invalidFiles.push({ file, errors: validation.errors });
}
}

return { validFiles, invalidFiles };
}
}

File processing with metadata

interface FileMetadata {
name: string;
size: number;
type: string;
lastModified: number;
lastModifiedDate: Date;
}

function extractFileMetadata(file: unknown): FileMetadata | null {
if (!isFile(file)) {
return null;
}

// TypeScript knows file is File with all File properties
return {
name: file.name,
size: file.size,
type: file.type,
lastModified: file.lastModified,
lastModifiedDate: new Date(file.lastModified)
};
}

async function processFileWithMetadata(file: unknown) {
const metadata = extractFileMetadata(file);

if (!metadata || !isFile(file)) {
throw new Error('Invalid file input');
}

console.log('File metadata:', metadata);

// Read file content
const content = await file.text();

return {
metadata,
content,
processed: true,
processedAt: new Date()
};
}

Drag and drop file handling

class FileDropHandler {
setupDropZone(element: HTMLElement) {
element.addEventListener('dragover', this.handleDragOver);
element.addEventListener('drop', this.handleDrop);
}

private handleDragOver = (event: DragEvent) => {
event.preventDefault();
event.stopPropagation();
};

private handleDrop = async (event: DragEvent) => {
event.preventDefault();
event.stopPropagation();

const files = Array.from(event.dataTransfer?.files || []);
const validFiles = files.filter(isFile);

if (validFiles.length !== files.length) {
console.warn(`${files.length - validFiles.length} invalid file objects detected`);
}

for (const file of validFiles) {
await this.processDroppedFile(file);
}
};

private async processDroppedFile(file: File) {
console.log(`Processing dropped file: ${file.name} (${file.size} bytes)`);

// Handle different file types
if (file.type.startsWith('image/')) {
await this.processImage(file);
} else if (file.type === 'text/plain') {
await this.processText(file);
} else {
console.log(`Unsupported file type: ${file.type}`);
}
}

private async processImage(file: File) {
const imageUrl = URL.createObjectURL(file);
// Process image...
URL.revokeObjectURL(imageUrl); // Clean up
}

private async processText(file: File) {
const text = await file.text();
console.log(`Text content: ${text.substring(0, 100)}...`);
}
}

File API feature detection

interface FileApiSupport {
file: boolean;
blob: boolean;
fileReader: boolean;
formData: boolean;
url: boolean;
}

function detectFileApiSupport(): FileApiSupport {
return {
file: typeof File !== 'undefined',
blob: typeof Blob !== 'undefined',
fileReader: typeof FileReader !== 'undefined',
formData: typeof FormData !== 'undefined',
url: typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function'
};
}

function createFileIfSupported(content: string, filename: string): File | null {
const support = detectFileApiSupport();

if (!support.file) {
console.warn('File API not supported');
return null;
}

const file = new File([content], filename, { type: 'text/plain' });

if (isFile(file)) {
return file;
}

console.error('Failed to create File object');
return null;
}

Playground

import { isFile } from '@winglet/common-utils';

// True cases - File instances (in browser environment)
if (typeof File !== 'undefined') {
const file1 = new File(['content'], 'test.txt', { type: 'text/plain' });
const file2 = new File(['<h1>Hello</h1>'], 'test.html', { type: 'text/html' });

console.log(isFile(file1)); // true
console.log(isFile(file2)); // true
}

// False cases - not File objects
console.log(isFile(new Blob(['content']))); // false (Blob, not File)
console.log(isFile('filename.txt')); // false (string)
console.log(isFile({ name: 'file.txt', size: 100 })); // false (file-like object)
console.log(isFile(null)); // false
console.log(isFile(undefined)); // false

// Environment without File API support (e.g., older Node.js)
console.log(isFile(anything)); // always false

Notes

File vs Blob Relationship:

  • File extends Blob with additional properties (name, lastModified)
  • All File objects are also Blob objects
  • This function specifically checks for File, not just Blob
  • Use isBlob() if you want to accept both File and Blob objects

Environment Compatibility:

  • File API is available in modern browsers
  • Not available in older browsers or some server environments
  • Node.js has limited File API support (may require polyfills)
  • Always check environment support before using

File Properties Available:

  • name - filename string
  • size - file size in bytes
  • type - MIME type string
  • lastModified - timestamp of last modification
  • All Blob methods: text(), arrayBuffer(), stream(), slice()

Use Cases:

  • File upload handling
  • Drag and drop file processing
  • File input validation
  • File metadata extraction
  • Client-side file processing

Performance: File and Blob instanceof checks with environment validation.

Related Functions:

  • Use isBlob() for Blob detection (includes File objects)
  • Use isArrayBuffer() for binary buffer detection
  • Use File API methods for file content access