Caveats & Gotchas
A few behaviours in pathlib-ts are intentionally different from both CPython and Node’s builtins. Understanding them upfront saves debugging time.
Async-first surface
Section titled “Async-first surface”- Methods that touch the filesystem are async by default. If you forget to
awaitcalls likeexists(), your conditionals will always see a truthy promise. Reach for theSyncvariants when you truly need blocking behaviour. Path.relativeTo()andPath.isRelativeTo()can also return promises whenextra.policy === "auto". TypeScript will flag this, but plain JavaScript migrations should double-check.
Lexical vs filesystem semantics
Section titled “Lexical vs filesystem semantics”PurePath.relativeTo()mirrors CPython: it throws when the anchors differ or when the target is not a true descendant (unlesswalkUp: true). Node’spath.relative()never throws, so migrations should addwalkUpand pick an appropriate policy onPath.relativeTo().PurePath.match()andfullMatch()operate on normalised path strings. They will not consult the filesystem and they treat case sensitivity according to the underlying parser (posixis case-sensitive,win32is not).
PurePath.name vs Dirent.name
Section titled “PurePath.name vs Dirent.name”Both values are strings but reference different concepts:
PurePath.namegives you the final component of the path (including suffixes).Dirent.nameis the filename/descriptor as read from the parent directory entry.
When you iterate with iterdir() (returning Path), entry.name delegates to the underlying PurePath.name, which is safe for joins and string comparisons. When you request native Dirent objects, keep using dirent.name as before. Mixing them up can introduce subtle bugs when handling trailing dots on Windows or UNC prefixes.
Runtime feature detection
Section titled “Runtime feature detection”UnsupportedOperationis raised when the host runtime lacks an API (e.g.fs.globSync,fs.readdir(..., { withFileTypes: true }), orfs.opendir). Catch it if you must support older Node versions.Path.copy()relies onfs.cpSync. On Node < 18.13 (or platforms withoutcpSync) you will also receiveUnsupportedOperation.
Normalization differences
Section titled “Normalization differences”- Like CPython,
PurePathcollapses duplicated separators and single dots but leaves..segments in place. CallPath.resolve()if you need them eliminated. Path.absolute()simply resolves the path against the current working directory without touching symlinks or..segments. Useresolve()for a fully canonical result.
Policy pitfalls
Section titled “Policy pitfalls”Path.relativeTo() supports three policies for handling symlinks and directory semantics:
extra.policy: "auto"(default) treats the right-hand operand as a directory when it exists as such on the filesystem. If it is a symlink to a directory, the link target is used. This matches JS/Node conventions but can differ from CPython behaviour.extra.policy: "parent"ignores the filesystem entirely. If the right-hand operand is a symlink to a directory, you may get results that differ frompolicy: "auto".extra.followSymlinksonly applies whenpolicy === "auto". Passing it with other policies is harmless but has no effect.
Glob behaviour
Section titled “Glob behaviour”- Recursive globbing (
**) follows CPython’s rules but requires Node 20+ (or Bun/Deno equivalents). Withoutfs.glob, glob calls throwUnsupportedOperation. - Patterns are interpreted relative to the receiver; passing absolute patterns mirrors Python but can be surprising in procedural code.
Copying and metadata
Section titled “Copying and metadata”Path.copy()setsrecursive: trueand delegates tofs.cp. Metadata preservation (preserveMetadata/followSymlinks) is best-effort and ultimately depends on the host runtime.- Low-level cloning strategies from CPython
_os.py(reflink,copy_file_range, etc.) are intentionally omitted for portability. For advanced use cases prefer manual streaming via Node APIs or thecopyFileObjhelper insrc/os.ts.
Cross-platform paths
Section titled “Cross-platform paths”- Instantiating
WindowsPathon POSIX (orPosixPathon Windows) throwsUnsupportedOperation, matching CPython. UsePureWindowsPath/PurePosixPathwhen you need to manipulate foreign-flavour paths without I/O. - UNC paths and drive-letter nuances follow
node:path.win32semantics. Tests cover common edge cases, but be cautious when converting between native strings and URIs.
PathLike (pathlib-ts vs Node)
Section titled “PathLike (pathlib-ts vs Node)”This library’s PathLike (in src/purepath.ts) is string | PurePath — an alias used to accept either raw strings or other path objects from pathlib-ts.
Node’s PathLike (the one in node:fs typings) is string | Buffer | URL. They are not the same type.
Handling optional runtime features
Section titled “Handling optional runtime features”Node < 20 (and some other runtime builds) do not ship fs.glob/fs.globSync. In those environments, calling Path.glob() raises UnsupportedOperation.
Same story for withFileTypes: true. The library mirrors the runtime capability rather than polyfilling it.