Node.js fs and fs/promises wrapped in neverthrow Result types for type-safe error handling
npm install @jvens/neverthrow-fs


A type-safe wrapper around Node.js fs and fs/promises APIs using neverthrow's Result and ResultAsync types for explicit error handling.
- Type-safe error handling: All file system operations return Result or ResultAsync
- Comprehensive coverage: Wraps all major fs and fs/promises functions
- Detailed error types: Specific error classes for different failure scenarios (FileNotFound, PermissionDenied, etc.)
- Tree-shakeable: Import only what you need
- Dual module support: CommonJS and ESM compatible
- Full TypeScript support: Accurate type definitions included
``bash`
npm install @jvens/neverthrow-fs neverthrow
Note: neverthrow is a peer dependency and must be installed separately.
`typescript
import { readFileSync, writeFileSync, existsSync } from '@jvens/neverthrow-fs';
// Reading a file
const result = readFileSync('/path/to/file.txt', 'utf8');
if (result.isOk()) {
console.log('File contents:', result.value);
} else {
console.error('Error reading file:', result.error.message);
console.error('Error type:', result.error.kind);
}
// Writing a file with error handling
const writeResult = writeFileSync('/path/to/output.txt', 'Hello, World!');
writeResult
.map(() => console.log('File written successfully'))
.mapErr((error) => console.error(Failed to write file: ${error.message}));
// Checking file existence
const exists = existsSync('/path/to/file.txt');
if (exists.isOk() && exists.value) {
console.log('File exists');
}
`
`typescript
import { readFile, writeFile, mkdir, stat } from '@jvens/neverthrow-fs';
// Reading a file asynchronously
const result = await readFile('/path/to/file.txt', 'utf8');
result
.map((contents) => console.log('File contents:', contents))
.mapErr((error) => console.error('Error:', error.message));
// Chaining operations
const processFile = await readFile('/input.txt', 'utf8')
.andThen(async (content) => {
const processed = content.toUpperCase();
return writeFile('/output.txt', processed);
});
if (processFile.isErr()) {
console.error('Operation failed:', processFile.error.message);
}
// Creating directories with proper error handling
const dirResult = await mkdir('/path/to/new/directory', { recursive: true });
if (dirResult.isErr()) {
if (dirResult.error.kind === 'FileAlreadyExistsError') {
console.log('Directory already exists');
} else {
console.error('Failed to create directory:', dirResult.error.message);
}
}
`
`typescript
import * as fs from '@jvens/neverthrow-fs';
const syncResult = fs.readFileSync('/file.txt', 'utf8');
const asyncResult = await fs.readFile('/file.txt', 'utf8');
`
The library provides specific error types for better error handling:
`typescript
import type { FsError, FsErrorKind } from '@jvens/neverthrow-fs';
// Available error types (strongly typed):
// - FileNotFoundError (ENOENT)
// - PermissionDeniedError (EACCES, EPERM)
// - DirectoryNotEmptyError (ENOTEMPTY)
// - FileAlreadyExistsError (EEXIST)
// - NotADirectoryError (ENOTDIR)
// - IsADirectoryError (EISDIR)
// - InvalidArgumentError (EINVAL)
// - IOError (other filesystem errors)
// - UnknownError (unexpected errors)
function handleError(error: FsError) {
// TypeScript will provide exhaustive checking and autocomplete
switch (error.kind) {
case 'FileNotFoundError':
console.log('File not found:', error.path);
break;
case 'PermissionDeniedError':
console.log('Permission denied for:', error.path);
break;
case 'FileAlreadyExistsError':
console.log('File already exists:', error.path);
break;
case 'DirectoryNotEmptyError':
console.log('Directory not empty:', error.path);
break;
case 'NotADirectoryError':
console.log('Not a directory:', error.path);
break;
case 'IsADirectoryError':
console.log('Is a directory:', error.path);
break;
case 'InvalidArgumentError':
console.log('Invalid argument:', error.message);
break;
case 'IOError':
console.log('I/O error:', error.message, error.code);
break;
case 'UnknownError':
console.log('Unknown error:', error.message);
break;
// TypeScript will ensure all cases are handled
}
}
// You can also use the FsErrorKind type directly
function isFileNotFound(errorKind: FsErrorKind): boolean {
return errorKind === 'FileNotFoundError';
}
`
All functions return Result:
- accessSync(path, mode?) - Test file permissionsappendFileSync(file, data, options?)
- - Append to filechmodSync(path, mode)
- - Change permissionschownSync(path, uid, gid)
- - Change ownershipcopyFileSync(src, dest, mode?)
- - Copy fileexistsSync(path)
- - Check if file existslinkSync(existingPath, newPath)
- - Create hard linkmkdirSync(path, options?)
- - Create directorymkdtempSync(prefix, options?)
- - Create temp directoryreaddirSync(path, options?)
- - Read dir contentsreadFileSync(path, options?)
- - Read filereadlinkSync(path, options?)
- - Read symlinkrealpathSync(path, options?)
- - Resolve pathrenameSync(oldPath, newPath)
- - Rename file/dirrmdirSync(path, options?)
- - Remove directoryrmSync(path, options?)
- - Remove files/dirsstatSync(path, options?)
- - Get file statslstatSync(path, options?)
- - Get file stats (no symlink follow)symlinkSync(target, path, type?)
- - Create symlinktruncateSync(path, len?)
- - Truncate fileunlinkSync(path)
- - Remove fileutimesSync(path, atime, mtime)
- - Update timestampswriteFileSync(file, data, options?)
- - Write file
All functions return ResultAsync:
- access(path, mode?) - Test file permissionsappendFile(file, data, options?)
- - Append to filechmod(path, mode)
- - Change permissionschown(path, uid, gid)
- - Change ownershipcopyFile(src, dest, mode?)
- - Copy filecp(src, dest, options?)
- - Copy recursivelylink(existingPath, newPath)
- - Create hard linklchown(path, uid, gid)
- - Change symlink ownershiplchmod(path, mode)
- - Change symlink permissionslutimes(path, atime, mtime)
- - Update symlink timestampsmkdir(path, options?)
- - Create directorymkdtemp(prefix, options?)
- - Create temp directoryopen(path, flags?, mode?)
- - Open file handleopendir(path, options?)
- - Open directoryreaddir(path, options?)
- - Read dir contentsreadFile(path, options?)
- - Read filereadlink(path, options?)
- - Read symlinkrealpath(path, options?)
- - Resolve pathrename(oldPath, newPath)
- - Rename file/dirrmdir(path, options?)
- - Remove directoryrm(path, options?)
- - Remove files/dirsstat(path, options?)
- - Get file statslstat(path, options?)
- - Get file stats (no symlink follow)symlink(target, path, type?)
- - Create symlinktruncate(path, len?)
- - Truncate fileunlink(path)
- - Remove fileutimes(path, atime, mtime)
- - Update timestampswatch(filename, options?)
- - Watch for changeswriteFile(file, data, options?)
- - Write file
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
`bashClone the repository
git clone https://github.com/jvens/neverthrow-fs.git
cd neverthrow-fs
This project is licensed under the MIT License - see the LICENSE file for details.
- neverthrow - The excellent Result type library this package builds upon
- Node.js fs module - The underlying filesystem API