Str — String Utilities
Strings are the primary medium for untrusted data entering our applications. Whether we are parsing HTTP headers, processing CSV uploads, or cleaning up user-submitted text fields, string transformation is a constant necessity.
In standard JavaScript, the String prototype offers a wide array of methods. However, because
these methods are “data-first” — called directly on the string object itself — they do not compose
cleanly. When we write functional pipelines using pipe, we are forced to wrap prototype calls in
anonymous arrow functions (e.g., s => s.trim()), which breaks the natural flow of data and
introduces visual noise.
Str provides standard string operations as pure, curried, data-last functions. It turns prototype
operations into modular building blocks that fit seamlessly into pipelines, alongside safe numeric
parsers that model parsing failures using the Maybe type.
The problem with prototype chaining and unsafe parsing
Section titled “The problem with prototype chaining and unsafe parsing”Consider a backend handler that parses a comma-separated list of tags from a form submission:
This prototype-chaining approach is familiar, but it only works when the operations are methods on the string class. The moment we want to mix in custom helpers, external validations, or conditional transformations, the chain breaks. We are forced to intercept the chain or assign intermediate variables:
Furthermore, standard parsing functions like parseInt are unsafe: they return NaN when given
invalid input, which silently propagates through calculations and eventually causes runtime errors
far from the source of the bad data.
The shift to pipeline-ready operations
Section titled “The shift to pipeline-ready operations”Str treats string transformations as independent, modular steps. By shifting the data argument to
the last position and currying the parameters, string operations can be composed point-free directly
inside pipe.
flowchart TD
A["Raw Input"] --> B["Str.trim"]
B --> C["Str.split(',')"]
C --> D["Arr.map(Str.trim)"]
D --> E["Arr.filter(Str.includes('...'))"]
Transforming cases and cleaning input
Section titled “Transforming cases and cleaning input”Basic formatting operations are wrapped as pure functions that fit cleanly into array transformations and pipe flows:
Splitting and segmenting text
Section titled “Splitting and segmenting text”Standard JavaScript split returns a plain array, but handles multi-line endings and multiple
spaces awkwardly. Str provides robust segmentation helpers:
Replacing text
Section titled “Replacing text”Str.replace and Str.replaceAll are curried wrappers around native string replacement. They
accept the search pattern and replacement string first, leaving the target string for last:
Reusable predicates for filtering
Section titled “Reusable predicates for filtering”String matching operations function as curried predicates, which can be passed directly to array filters:
Safe numeric parsing
Section titled “Safe numeric parsing”Str.parse provides two safe alternatives to standard number parsing. Both Str.parse.int and
Str.parse.float inspect the string and return a Maybe<number> context, eliminating the need for
boilerplate isNaN checks:
These safe parsers compose cleanly to resolve safe fallback defaults:
Composing a string pipeline
Section titled “Composing a string pipeline”By combining these utilities, we can assemble multi-step text cleanup pipelines that are self-documenting and highly maintainable:
When to use Str vs prototype methods
Section titled “When to use Str vs prototype methods”Use Str when
Section titled “Use Str when”- You are transforming strings within a functional pipeline using
pipeand want to keep a consistent point-free style. - You are mapping or filtering collections of strings and want clean, named predicates instead of inline lambdas.
- You are parsing numeric strings and want to handle validation safety explicitly using the
Maybetype. - You need to parse multi-line inputs or space-separated lists, utilizing
linesandwordsto handle edge cases automatically.
Use prototype methods when
Section titled “Use prototype methods when”- You are writing a simple, self-contained statement in imperative code where direct method calls are highly readable.
- You need locale-sensitive comparisons or transformations (e.g.
localeCompare,toLocaleLowerCase).