Str
String utilities for text manipulation and analysis.
Provides comprehensive string operations including case conversion, splitting, matching, replacement, templating, and character utilities. Features type-safe APIs with strong inference for string literals and patterns.
Import
import { Str } from '@wollybeard/kit'
import * as Str from '@wollybeard/kit/str'
Namespaces
Provides tools for generating markdown, TSDoc/JSDoc, and TypeScript code. Includes safe JSDoc generation with escaping, builder API, and structured tag helpers.
Text
- Multi-line text formatting and layout utilities.
Provides functions specifically for working with multi-line strings treated as text content: - Line operations: Split into lines, join lines, map transformations per line - Indentation: Add/remove indentation, strip common leading whitespace - Alignment: Pad text, span to width, fit to exact width - Block formatting: Format blocks with prefixes, styled borders
Use Text for: Operations that treat strings as multi-line content with visual layout (indentation, padding for tables, line-by-line transformations).
Use root Str for: Primitive string operations (split, join, replace, match, trim) that work on strings as atomic values.
Visual
- Visual-aware string utilities that handle ANSI escape codes and grapheme clusters.
These functions measure and manipulate strings based on their visual appearance, not raw character count. Useful for terminal output, tables, and formatted text.
Builder
[C]
defaultRender
;((value: string[]) => string)
Default render function for string builders. Joins lines with newline characters.
[I]
Builder
interface Builder {
/**
* Add lines to the builder.
* @param linesInput - Lines to add (null values are filtered out)
* @returns The builder instance for chaining
*/
(...linesInput: LinesInput): Builder
/**
* Add content using template literal syntax.
* @param strings - Template string array
* @param values - Interpolated values
* @returns The builder instance for chaining
*/
(strings: TemplateStringsArray, ...values: string[]): Builder
/**
* The internal state containing accumulated lines.
*/
state: State
/**
* Render the accumulated lines into a single string.
* @returns The rendered string
*/
render: () => string
/**
* Alias for render() to support string coercion.
* @returns The rendered string
*/
toString(): string
}
String builder interface for constructing multi-line strings. Supports both function call syntax and template literal syntax.
[F]
Builder
(options?: { join?: string; } | undefined): Builder
Returns: A new builder instance
Create a new string builder for constructing multi-line strings.
Examples:
const b = Str.Builder()
b('Line 1')
b('Line 2', 'Line 3')
b`Template line`
console.log(b.render()) // "Line 1\nLine 2\nLine 3\nTemplate line"
[T]
LinesInput
type LinesInput = (Line | null)[]
Input type for lines
- allows null values which are filtered out.
[T]
Lines
type Lines = Line[]
Array of line strings.
[T]
Line
type Line = string
A single line of text.
[I]
State
interface State {
/**
* Accumulated lines.
*/
lines: Lines
}
Internal state of the string builder.
Constants
[C]
Empty
''
Empty string constant.
Examples:
const result = someCondition ? 'hello' : Empty
Formatting
[F]
table
(input: { data: Record<string, string>; separator?: string | false | undefined; separatorAlignment?: boolean; }): string
Parameters:
input
- Configuration object
Returns: Formatted table string with aligned columns
Format a key-value object as an aligned table string.
Examples:
Str.table({
data: { name: 'John', age: '25', city: 'NYC' },
})
// Returns:
// name → John
// age → 25
// city → NYC
Str.table({
data: { foo: 'bar', hello: 'world' },
separator: ' = ',
separatorAlignment: false,
})
// Returns:
// foo = bar
// hello = world
Pattern Matching
[F]
pattern
<matches extends Matches>(pattern: RegExp): Pattern<matches>
Parameters:
pattern
- The regular expression pattern
Returns: A typed pattern that preserves capture group information
Create a typed pattern from a regular expression. Enables type-safe capture groups when used with match.
Examples:
const p = pattern<{ groups: ['name', 'age'] }>(/(?<name>\w+) is (?<age>\d+)/)
const result = match('John is 25', p)
if (Option.isSome(result)) {
console.log(result.value.groups.name) // 'John' (typed)
console.log(result.value.groups.age) // '25' (typed)
}
[F]
match
<matches extends Matches>(string: string, pattern: RegExp | Pattern<matches>): Option<RegExpMatchResult<matches>>
Parameters:
string
- The string to match againstpattern
- Regular expression or typed pattern
Returns: Option of match result with typed capture groups, or None if no match
Match a string against a pattern with type-safe results.
Examples:
const result = Str.match('hello world', /hello (\w+)/)
if (Option.isSome(result)) {
console.log(result.value[0]) // 'hello world'
console.log(result.value[1]) // 'world'
}
Predicates
[F]
isMatch
(value: string, pattern: PatternInput): boolean
Parameters:
value
- The string to testpattern
- String for exact match or RegExp for pattern match
Returns: True if the value matches the pattern
Check if a string matches a pattern.
Examples:
Str.isMatch('hello', 'hello') // true
Str.isMatch('hello', /^h.*o$/) // true
Str.isMatch('world', 'hello') // false
[C]
isMatchOn
;((value: string) => (pattern: PatternInput) => boolean)
Curried version of isMatch with value first.
Examples:
const isHello = Str.isMatchOn('hello')
isHello('hello') // true
isHello(/^h.*o$/) // true
[C]
isMatchWith
;((pattern: PatternInput) => (value: string) => boolean)
Curried version of isMatch with pattern first.
Examples:
const matchesHello = Str.isMatchWith('hello')
matchesHello('hello') // true
matchesHello('world') // false
[F]
isntMatch
(pattern: PatternInput): (value: string) => boolean
Parameters:
pattern
- String for exact match or RegExp for pattern match
Returns: Function that takes a value and returns true if it doesn't match
Check if a string does not match a pattern.
Examples:
const notHello = Str.isntMatch('hello')
notHello('world') // true
notHello('hello') // false
[C]
isntMatchOn
;((pattern: PatternInput) => (value: string) => boolean)
Curried version of isntMatch with value first.
[C]
isntMatchWith
;((value: string) => (pattern: PatternInput) => boolean)
Curried version of isntMatch with pattern first.
[F]
isMatchAny
(value: string, patterns: PatternsInput): boolean
Parameters:
value
- The string to testpatterns
- Array of strings or RegExp patterns (or a single pattern)
Returns: True if the value matches any pattern
Check if a string matches any of the provided patterns.
Examples:
Str.isMatchAny('hello', ['hello', 'world']) // true
Str.isMatchAny('hello', [/^h/, /o$/]) // true
Str.isMatchAny('foo', ['hello', 'world']) // false
[C]
isMatchAnyOn
;((value: string) => (patterns: PatternsInput) => boolean)
Curried version of isMatchAny with value first.
[C]
isMatchAnyWith
;((patterns: PatternsInput) => (value: string) => boolean)
Curried version of isMatchAny with patterns first.
Examples:
const matchesGreeting = Str.isMatchAnyWith(['hello', 'hi', /^hey/])
matchesGreeting('hello') // true
matchesGreeting('hey there') // true
matchesGreeting('goodbye') // false
[F]
isNotMatchAny
(patternOrPatterns: PatternsInput): (value: string) => boolean
Parameters:
patternOrPatterns
- Array of strings or RegExp patterns (or a single pattern)
Returns: Function that takes a value and returns true if it doesn't match any pattern
Check if a string does not match any of the provided patterns.
Examples:
const notGreeting = Str.isNotMatchAny(['hello', 'hi'])
notGreeting('goodbye') // true
notGreeting('hello') // false
[C]
isNotMatchAnyOn
;((patternOrPatterns: PatternsInput) => (value: string) => boolean)
Curried version of isNotMatchAny with value first.
[C]
isNotMatchAnyWith
;((value: string) => (patternOrPatterns: PatternsInput) => boolean)
Curried version of isNotMatchAny with patterns first.
Template
[F]
interpolate
(template: string): (args: TemplateArgs) => string
Parameters:
template
- Template string containing $variable placeholders
Returns: Function that takes args object and returns interpolated string
Interpolate variables into a template string using $variable syntax.
Examples:
const greeting = Str.interpolate('Hello ${name}, you are ${age} years old')
greeting({ name: 'John', age: 25 }) // 'Hello John, you are 25 years old'
const template = Str.interpolate('${greeting} ${name}!')
template({ greeting: 'Hi', name: 'Alice' }) // 'Hi Alice!'
[C]
templateVariablePattern
RegExp
Regular expression pattern to match template variables in $variable format. Captures the variable name inside the braces.
[T]
TemplateArgs
type TemplateArgs = Record<string, Json.Value>
Arguments object for template interpolation. Maps variable names to their JSON-serializable values.
Text Formatting
[Class]
Box
class {
// Properties
paddingHooks: Partial<Record<"mainStart" | "mainEnd" | "crossStart" | "crossEnd", ((ctx: any) => number | ((v: number) => number))[]>>
marginHooks: Partial<Record<"mainStart" | "mainEnd" | "crossStart" | "crossEnd", ((ctx: any) => number | ((v: number) => number))[]>>
borderEdgeHooks: Partial<Record<"left" | "right" | "top" | "bottom", ((ctx: any) => string | ((v: string) => string))[]>>
borderCornerHooks: Partial<Record<"topLeft" | "topRight" | "bottomRight" | "bottomLeft", ((ctx: any) => string | ((v: string) => string))[]>>
borderEdgeStyles: Partial<Record<"left" | "right" | "top" | "bottom", Style>>
borderCornerStyles: Partial<Record<"topLeft" | "topRight" | "bottomRight" | "bottomLeft", Style>>
static String: transformOrFail<typeof Box, typeof String, never>
// Methods
toString(): string
content$(content: string | (string | Box)[]): this
pad$(padding: PaddingInput): this
margin$(margin: MarginInput): this
border$(border: BorderInput): this
span$(span: SpanInput): this
spanRange$(spanRange: { readonly main?: { readonly min?: number | undefined; readonly max?: number | undefined; } | undefined; readonly cross?: { readonly min?: number | undefined; readonly max?: number | undefined; } | undefined; }): this
gap$(gap: GapInput): this
static content(box: Box, content: string | (string | Box)[]): Box
static pad(box: Box, padding: PaddingInput): Box
static margin(box: Box, margin: MarginInput): Box
static border(box: Box, border: BorderInput): Box
static span(box: Box, span: SpanInput): Box
static spanRange(box: Box, spanRange: { readonly main?: { readonly min?: number | undefined; readonly max?: number | undefined; } | undefined; readonly cross?: { readonly min?: number | undefined; readonly max?: number | undefined; } | undefined; }): Box
static gap(box: Box, gap: GapInput): Box
static encode(box: Box): string
}
Properties:
String
- Schema for encoding Box to string representation.
This is a one-way transformation - boxes can be encoded to strings, but cannot be decoded from strings.
Box structure with content and optional styling.
[C]
OrientationSchema
Literal<['vertical', 'horizontal']>
Orientation determines the flow direction of the box.
vertical
: Content flows top-to-bottom (main axis = vertical)horizontal
: Content flows left-to-right (main axis = horizontal)
[T]
Orientation
type Orientation = typeof OrientationSchema.Type
Orientation type.
[C]
PaddingSchema
Struct<
{
mainStart: optional<typeof Number>
mainEnd: optional<typeof Number>
crossStart: optional<typeof Number>
crossEnd: optional<typeof Number>
}
>
Padding configuration using logical properties.
Logical properties adapt to orientation:
mainStart
/mainEnd
: Along the flow directioncrossStart
/crossEnd
: Perpendicular to flow
[T]
Padding
type Padding = typeof PaddingSchema.Type
Padding configuration type.
[U]
PaddingInput
type PaddingInput = AxisHand.Input | WithHooks<Padding, 'padding'>
Padding input accepting AxisHand notation and hook functions.
Supports AxisHand patterns:
- Single value:
2
→ all sides - Axis shorthands:
[2, 4]
→ [main, cross] - Binary axis:
[[1, 2], [3, 4]]
→ [[mainStart, mainEnd], [crossStart, crossEnd]] - Per-axis arrays:
[[1, 2], 4]
→ asymmetric main, symmetric cross - Object:
{ main: [1, 2], cross: 4 }
- With hooks:
{ main: { start: (ctx) => 2 } }
[C]
MarginSchema
Struct<
{
mainStart: optional<typeof Number>
mainEnd: optional<typeof Number>
crossStart: optional<typeof Number>
crossEnd: optional<typeof Number>
}
>
Margin configuration using logical properties.
Logical properties adapt to orientation (same as Padding).
[T]
Margin
type Margin = typeof MarginSchema.Type
Margin configuration type.
[U]
MarginInput
type MarginInput = AxisHand.Input | WithHooks<Margin, 'margin'>
Margin input accepting AxisHand notation and hook functions.
Supports AxisHand patterns (same as PaddingInput).
[U]
SpanValue
type SpanValue = number | bigint
Span value type
size in characters or percentage of parent.
number
(1): Absolute size in charactersbigint
: Percentage of parent span (e.g.,50n
= 50%)
[C]
SpanSchema
Struct<
{
main: optional<Union<[typeof Number, typeof BigIntFromSelf]>>
cross: optional<Union<[typeof Number, typeof BigIntFromSelf]>>
}
>
Span configuration using logical properties.
Defines exact/desired size along each axis:
main
: Size along flow direction (mainSpan)cross
: Size perpendicular to flow (crossSpan)
Percentage values (bigint) are resolved relative to parent's available span.
[T]
Span
type Span = typeof SpanSchema.Type
Span configuration type.
[T]
SpanInput
type SpanInput = AxisHand.Input<SpanValue>
Span input accepting AxisHand notation.
Supports AxisHand patterns with SpanValue (number | bigint):
- Single value:
80
→ main and cross both 80 chars - Single percentage:
50n
→ main and cross both 50% of parent - Axis shorthands:
[50n, 80]
→ main 50%, cross 80 chars - Binary axis:
[[40, 50n], [80, 100]]
→ different start/end (unusual for span) - Object:
{ main: 50n, cross: 80 }
[C]
SpanRangeSchema
Struct<
{
main: optional<
Struct<{ min: optional<typeof Number>; max: optional<typeof Number> }>
>
cross: optional<
Struct<{ min: optional<typeof Number>; max: optional<typeof Number> }>
>
}
>
Span range constraints (min/max) using logical properties.
[T]
SpanRange
type SpanRange = typeof SpanRangeSchema.Type
Span range configuration type.
[C]
GapSchema
Struct<{ main: optional<typeof Number>; cross: optional<typeof Number> }>
Gap configuration using logical properties.
Defines space between array items (container property):
- Vertical orientation: main=newlines between items, cross=spaces between items
- Horizontal orientation: main=spaces between items, cross=newlines between items
[T]
Gap
type Gap = typeof GapSchema.Type
Gap configuration type.
[U]
GapInput
type GapInput = number | Gap
Gap input accepting number or object with logical properties.
number
: Same gap on both axes{ main?: number, cross?: number }
: Per-axis gaps
[C]
BorderStyleSchema
Literal<['single', 'double', 'rounded', 'bold', 'ascii']>
Border style presets.
[T]
BorderStyle
type BorderStyle = typeof BorderStyleSchema.Type
Border style preset type.
[C]
BorderEdgesSchema
Struct<
{
top: optional<typeof String>
right: optional<typeof String>
bottom: optional<typeof String>
left: optional<typeof String>
}
>
Border edge characters (physical coordinates).
[T]
BorderEdges
type BorderEdges = typeof BorderEdgesSchema.Type
Border edge configuration type.
[C]
BorderCornersSchema
Struct<
{
topLeft: optional<typeof String>
topRight: optional<typeof String>
bottomRight: optional<typeof String>
bottomLeft: optional<typeof String>
}
>
Border corner characters (physical coordinates).
[T]
BorderCorners
type BorderCorners = typeof BorderCornersSchema.Type
Border corner configuration type.
[U]
BorderEdgesInput
type BorderEdgesInput =
| Clockhand.Value<string | CharStyle>
| WithHooks<BorderEdges, 'border.edges'>
| {
[K in keyof BorderEdges]?:
| string
| CharStyle
| WithHook<
string | undefined,
StyleCategoryMap[`border.edges.${K & string}`]
>
}
Border edge input supporting Clockhand notation, CharStyle, and hook functions.
Supports Clockhand patterns:
- Single value:
'─'
→ all edges - Single styled:
{ char: '─', color: { foreground: 'blue' } }
→ all edges - Array:
['─', '│', '─', '│']
→ [top, right, bottom, left] - Object:
{ top: '─', left: '│' }
- Object with CharStyle:
{ top: { char: '─', color: { foreground: 'red' } } }
- With hooks:
{ top: (ctx) => '─' }
[U]
BorderCornersInput
type BorderCornersInput =
| Clockhand.Value<string | CharStyle>
| WithHooks<BorderCorners, 'border.corners'>
| {
[K in keyof BorderCorners]?:
| string
| CharStyle
| WithHook<
string | undefined,
StyleCategoryMap[`border.corners.${K & string}`]
>
}
Border corner input supporting Clockhand notation, CharStyle, and hook functions.
Supports Clockhand patterns:
- Single value:
'+'
→ all corners - Single styled:
{ char: '+', color: { foreground: 'yellow' }, bold: true }
→ all corners - Array:
['┌', '┐', '┘', '└']
→ [topLeft, topRight, bottomRight, bottomLeft] (clockwise) - Object:
{ topLeft: '┌', topRight: '┐' }
- Object with CharStyle:
{ topLeft: { char: '┌', color: { foreground: 'red' }, bold: true } }
- With hooks:
{ topLeft: (ctx) => '┌' }
[T]
BorderCharsInput
type BorderCharsInput = {
edges?: BorderEdgesInput
corners?: BorderCornersInput
}
Border character configuration input with nested edges/corners.
[C]
BorderSchema
Struct<
{
style: optional<Literal<['single', 'double', 'rounded', 'bold', 'ascii']>>
edges: optional<
Struct<
{
top: optional<typeof String>
right: optional<typeof String>
bottom: optional<typeof String>
left: optional<typeof String>
}
>
>
corners: optional<
Struct<
{
topLeft: optional<typeof String>
topRight: optional<typeof String>
bottomRight: optional<typeof String>
bottomLeft: optional<typeof String>
}
>
>
}
>
Border configuration.
Can specify a preset style, custom edges, custom corners, or a combination. Resolution order: style → edges override → corners override.
[T]
Border
type Border = typeof BorderSchema.Type
Border configuration type.
[T]
BorderInput
type BorderInput = {
style?: BorderStyle
edges?: BorderEdgesInput
corners?: BorderCornersInput
}
Border configuration input with hook support.
Supports:
style
: Preset border style (provides edges and corners)edges
: Edge characters (with Clockhand support)corners
: Corner characters (with Clockhand support)
Resolution order: style → edges/corners override
[U]
BoxContent
type BoxContent = string | StyledText | readonly (string | StyledText | Box)[]
Content type for Box
- can be a string, styled text, or array of these and boxes.
Supports:
- Plain strings:
'Hello'
- Styled text:
{ text: 'Hello', color: { foreground: 'red' }, bold: true }
- Arrays:
['Header', { text: 'Body', color: { foreground: 'green' } }, Box.make(...)]
Traits
[C]
Eq
Eq<string>
Eq trait implementation for strings.
Provides string equality comparison using strict equality (===). String comparison is case-sensitive and considers all Unicode characters.
Examples:
import { Str } from '@wollybeard/kit'
Str.Eq.is('hello', 'hello') // true
Str.Eq.is('hello', 'Hello') // false (case-sensitive)
Str.Eq.is('', '') // true (empty strings)
[C]
Type
Type<string>
Type trait implementation for strings.
Provides type guard for checking if a value is a string.
Examples:
import { Str } from '@wollybeard/kit'
Str.Type.is('hello') // true
Str.Type.is(123) // false
Str.Type.is(null) // false
Transformation
[F]
titlizeSlug
(str: string): string
Parameters:
str
- The slug string to convert
Returns: The title-cased string
Convert a URL slug to title case. Replaces URL path separators with spaces and converts to title case.
Examples:
Str.titlizeSlug('foo/bar/baz') // 'Foo Bar Baz'
Str.titlizeSlug('the/quick/brown/fox') // 'The Quick Brown Fox'
Str.titlizeSlug('hello-world') // 'Hello-World' (hyphens are preserved)
[F]
ensureEnd
(string: string, ending: string): string
Parameters:
string
- The string to checkending
- The ending to ensure
Returns: The string with the ending ensured
Ensure a string ends with a specific ending, adding it if not present.
[F]
trim
(value: string): string
Parameters:
value
- The string to trim
Returns: The trimmed string
DEPRECATED
Use String.trim from Effect instead
Remove whitespace from both ends of a string.
Examples:
Str.trim(' hello ') // 'hello'
Str.trim('\n\thello\n\t') // 'hello'
[F]
replaceLeading
(replacement: string, matcher: string, value: string): string
Parameters:
replacement
- The string to replace the matcher withmatcher
- The string to match at the beginningvalue
- The string to operate on
Returns: The string with leading matcher replaced
Replace the leading occurrence of a matcher string with a replacement.
Examples:
Str.replaceLeading('$', '//', '// comment') // '$ comment'
Str.replaceLeading('', 'www.', 'www.example.com') // 'example.com'
[F]
replaceLeadingWith
(replacement: string): (matcher: string) => (value: string) => string
Parameters:
replacement
- The string to replace the matcher with
Returns: Function that takes matcher, then value
Curried version of replaceLeading with replacement first.
[F]
replaceLeadingOn
(value: string): (replacement: string) => (matcher: string) => string
Parameters:
value
- The string to operate on
Returns: Function that takes replacement, then matcher
Curried version of replaceLeading with value first.
[C]
stripLeading
;((matcher: string) => (value: string) => string)
Remove the leading occurrence of a matcher string. Alias for replaceLeadingWith('')
.
Examples:
const removePrefix = Str.stripLeading('//')
removePrefix('// comment') // ' comment'
[F]
replace
(replacement: string, matcher: PatternsInput, value: string): string
Parameters:
replacement
- The string to replace matches withmatcher
- String or RegExp pattern(s) to matchvalue
- The string to operate on
Returns: The string with all matches replaced
DEPRECATED
Use String.replace or String.replaceAll from Effect instead
Replace all occurrences of patterns with a replacement string.
Examples:
Str.replace('_', ' ', 'hello world') // 'hello_world'
Str.replace('X', /[aeiou]/g, 'hello') // 'hXllX'
Str.replace('-', [' ', '_'], 'hello world_test') // 'hello-world-test'
[F]
replaceWith
(replacement: string): (matcher: PatternsInput) => (value: string) => string
Parameters:
replacement
- The string to replace matches with
Returns: Function that takes matcher, then value
Curried version of replace with replacement first.
[F]
replaceOn
(value: string): (replacement: string) => (matcher: PatternsInput) => string
Parameters:
value
- The string to operate on
Returns: Function that takes replacement, then matcher
Curried version of replace with value first.
[F]
append
(value1: string, value2: string): string
Parameters:
value1
- The base stringvalue2
- The string to append
Returns: The concatenated string
DEPRECATED
Use String.concat from Effect instead
Append a string to another string.
Examples:
Str.append('hello', ' world') // 'hello world'
Str.append('foo', 'bar') // 'foobar'
[C]
appendOn
;((value1: string) => (value2: string) => string)
Curried version of append with value1 first.
[C]
appendWith
;((value2: string) => (value1: string) => string)
Curried version of append with value2 first.
Examples:
const addWorld = Str.appendWith(' world')
addWorld('hello') // 'hello world'
[F]
prepend
(value1: string, value2: string): string
Parameters:
value1
- The string to prependvalue2
- The base string
Returns: The concatenated string with value1 first
DEPRECATED
Use String.concat from Effect instead (with arguments swapped)
Prepend a string to another string.
Examples:
Str.prepend('hello ', 'world') // 'hello world'
Str.prepend('pre', 'fix') // 'prefix'
[C]
prependOn
;((value1: string) => (value2: string) => string)
Curried version of prepend with value1 first.
[C]
prependWith
;((value2: string) => (value1: string) => string)
Curried version of prepend with value2 first.
Examples:
const toWorld = Str.prependWith('world')
toWorld('hello ') // 'hello world'
[F]
repeat
(value: string, count: number): string
Parameters:
value
- The string to repeatcount
- The number of times to repeat
Returns: The repeated string
DEPRECATED
Use String.repeat from Effect instead
Repeat a string a specified number of times.
Examples:
Str.repeat('a', 3) // 'aaa'
Str.repeat('hello', 2) // 'hellohello'
Str.repeat('-', 10) // '----------'
[C]
repeatOn
;((value: string) => (count: number) => string)
Curried version of repeat with value first.
[C]
repeatWith
;((count: number) => (value: string) => string)
Curried version of repeat with count first.
Examples:
const triple = Str.repeatWith(3)
triple('ha') // 'hahaha'
[F]
removeSurrounding
(str: string, target: string): string
Parameters:
str
- The string to processtarget
- The character to remove from both ends
Returns: The string with surrounding target characters removed
Remove all occurrences of a target character from the beginning and end of a string.
Examples:
Str.removeSurrounding(' hello ', ' ') // 'hello'
Str.removeSurrounding('***test***', '*') // 'test'
Str.removeSurrounding('aaa', 'a') // ''
[C]
removeSurroundingOn
;((str: string) => (target: string) => string)
Curried version of removeSurrounding with str first.
[C]
removeSurroundingWith
;((target: string) => (str: string) => string)
Curried version of removeSurrounding with target first.
[F]
truncate
(str: string, maxLength?: number = 80): string
Parameters:
str
- The string to truncatemaxLength
- Maximum length of the result (default: 80)
Returns: The truncated string with ellipsis if needed
Truncate a string to a maximum length, adding ellipsis if truncated.
Examples:
Str.truncate('hello world', 8) // 'hello...'
Str.truncate('short', 10) // 'short'
Str.truncate('very long text that needs truncating') // 'very long text that needs truncating...' (if > 80 chars)
[C]
truncateOn
;((str: string) => (maxLength?: number | undefined) => string)
Curried version of truncate with str first.
[C]
truncateWith
;((maxLength?: number | undefined) => (str: string) => string)
Curried version of truncate with maxLength first.
Examples:
const truncate10 = Str.truncateWith(10)
truncate10('hello world') // 'hello w...'
[C]
strip
;((matcher: PatternsInput) => (value: string) => string)
Remove all occurrences of patterns from a string. Alias for replaceWith('')
.
Examples:
const removeVowels = Str.strip(/[aeiou]/g)
removeVowels('hello world') // 'hll wrld'
[C]
removeSurroundingSpaceRegular
;((str: string) => string)
Remove regular spaces from the beginning and end of a string. Pre-configured removeSurroundingWith for regular spaces.
[C]
removeSurroundingSpaceNoBreak
;((str: string) => string)
Remove non-breaking spaces from the beginning and end of a string. Pre-configured removeSurroundingWith for non-breaking spaces.
[F]
split
(value: string, separator: string): string[]
Parameters:
value
- The string to splitseparator
- The separator to split on
Returns: Array of substrings
DEPRECATED
Use String.split from Effect instead
Split a string into an array of substrings using a separator.
Examples:
Str.split('a,b,c', ',') // ['a', 'b', 'c']
Str.split('hello world', ' ') // ['hello', 'world']
Str.split('', ',') // []
[C]
splitOn
(value: string) => (separator: string) => string[]
Curried version of split with value first.
[C]
splitWith
(separator: string) => (value: string) => string[]
Curried version of split with separator first.
Examples:
const splitByComma = Str.splitWith(',')
splitByComma('a,b,c') // ['a', 'b', 'c']
[F]
join
(value: string[], separator: string): string
Parameters:
value
- Array of strings to joinseparator
- The separator to place between strings
Returns: The joined string
DEPRECATED
Use Array.join from Effect instead
Join an array of strings into a single string with a separator.
Examples:
Str.join(['a', 'b', 'c'], ',') // 'a,b,c'
Str.join(['hello', 'world'], ' ') // 'hello world'
Str.join([], ',') // ''
[C]
joinOn
;((value: string[]) => (separator: string) => string)
Curried version of join with value first.
[C]
joinWith
;((separator: string) => (value: string[]) => string)
Curried version of join with separator first.
Examples:
const joinWithComma = Str.joinWith(',')
joinWithComma(['a', 'b', 'c']) // 'a,b,c'
[F]
merge
(string1: string, string2: string): string
Parameters:
string1
- The first stringstring2
- The second string
Returns: The concatenated string
DEPRECATED
Use String.concat from Effect instead
Merge two strings together (concatenate).
Examples:
Str.merge('hello', ' world') // 'hello world'
Str.merge('foo', 'bar') // 'foobar'
[C]
mergeOn
;((string1: string) => (string2: string) => string)
Curried version of merge with string1 first.
Examples:
const mergeWithHello = Str.mergeOn('hello')
mergeWithHello(' world') // 'hello world'
Type Guards
[F]
isEmpty
(value: string): boolean
Parameters:
value
- The string to check
Returns: True if the string is empty
DEPRECATED
Use String.isEmpty from Effect instead
Type guard to check if a string is empty.
Examples:
Str.isEmpty('') // true
Str.isEmpty('hello') // false
Str.isEmpty(' ') // false
Type Utilities
[T]
Empty
type Empty = ''
Type for an empty string.
Type-Level Utilities
[T]
EndsWith
type EndsWith<S extends string, T extends string> = S extends `${string}${T}`
? true
: false
Check if a string ends with a specific suffix.
[T]
StartsWith
type StartsWith<S extends string, T extends string> = S extends `${T}${string}`
? true
: false
Check if a string starts with a specific prefix.
[T]
LastSegment
type LastSegment<S extends string> = S extends `${string}/${infer Rest}`
? LastSegment<Rest>
: S
Extract the last segment from a path-like string (after the last '/').
[T]
RemoveTrailingSlash
type RemoveTrailingSlash<S extends string> = S extends `${infer Rest}/`
? Rest extends '' ? '/' : Rest
: S
Remove trailing slash from a string.
[T]
Split
type Split<S extends string, D extends string, Acc extends string[] = []> =
S extends '' ? Acc
: S extends `${infer Segment}${D}${infer Rest}`
? Segment extends '' ? Split<Rest, D, Acc>
: Segment extends '.' ? Split<Rest, D, Acc>
: Split<Rest, D, [...Acc, Segment]>
: S extends '.' ? Acc
: [...Acc, S]
Split a string by a delimiter, filtering out empty segments and '.' segments. This is useful for path-like strings.
[T]
Contains
type Contains<S extends string, C extends string> = S extends
`${string}${C}${string}` ? true : false
Check if string contains a character.
Type-Level Utilities $S - The string to measure $Acc - Accumulator tuple for counting (internal)
[T]
Length
type Length<$S extends string, $Acc extends 0[] = []> = $S extends
`${string}${infer __rest__}` ? Length<__rest__, [...$Acc, 0]>
: $Acc['length']
Get the length of a string type using tuple counting.
Uses recursive template literal parsing with tuple accumulation to count characters. Limited by TypeScript's recursion depth (typically ~50 levels).
Examples:
type L1 = Str.Length<'hello'> // 5
type L2 = Str.Length<''> // 0
type L3 = Str.Length<'a'> // 1
Type-Level Utilities $S - The string to pad $TargetLen - The desired final length $Fill - The character to use for padding (default: '_') $Acc - Accumulator for recursion depth tracking (internal)
[T]
PadEnd
type PadEnd<
$S extends string,
$TargetLen extends number,
$Fill extends string = '_',
$Acc extends 0[] = [],
> = Length<$S> extends $TargetLen ? $S
: $Acc['length'] extends 50 // Recursion limit safety
? $S
: PadEnd<`${$S}${$Fill}`, $TargetLen, $Fill, [...$Acc, 0]>
Pad a string to a target length by appending a fill character.
If the string is already at or exceeds the target length, returns it unchanged. Limited by TypeScript's recursion depth (~50 iterations).
Examples:
type P1 = Str.PadEnd<'foo', 10, '_'> // 'foo_______'
type P2 = Str.PadEnd<'hello', 3, '_'> // 'hello' (already longer)
type P3 = Str.PadEnd<'abc', 5, '0'> // 'abc00'
Type-Level Utilities $S - The string to pad $TargetLen - The desired final length $Fill - The character to use for padding (default: '0') $Acc - Accumulator for recursion depth tracking (internal)
[T]
PadStart
type PadStart<
$S extends string,
$TargetLen extends number,
$Fill extends string = '0',
$Acc extends 0[] = [],
> = Length<$S> extends $TargetLen ? $S
: $Acc['length'] extends 50 // Recursion limit safety
? $S
: PadStart<`${$Fill}${$S}`, $TargetLen, $Fill, [...$Acc, 0]>
Pad a string to a target length by prepending a fill character.
If the string is already at or exceeds the target length, returns it unchanged. Limited by TypeScript's recursion depth (~50 iterations).
Examples:
type P1 = Str.PadStart<'42', 5, '0'> // '00042'
type P2 = Str.PadStart<'hello', 3, '0'> // 'hello' (already longer)
type P3 = Str.PadStart<'x', 3, ' '> // ' x'
Type-Level Utilities T - The string type to check $ErrorMessage - Custom error message to display when T is not a literal
[T]
LiteralOnly
type LiteralOnly<
T extends string,
$ErrorMessage extends string = 'Expected a literal string',
> = string extends T ? Ts.StaticError<
$ErrorMessage,
{ ReceivedType: T },
'Use a string literal instead of string type'
>
: T
Constraint that only accepts literal strings. Returns StaticError for non-literal string type with customizable error message.
Other
[C]
Arb
Arb<string>
[I]
Box
interface Box {
readonly content: BoxContent
}
[∩]
RegExpMatchResult
type RegExpMatchResult<$Matches extends Matches> =
& Omit<RegExpMatchArray, 'groups'>
& {
groups: $Matches['groups'] extends
readonly [MatchItem, ...readonly MatchItem[]]
? ArrMut.ReduceWithIntersection<ToGroupsProperties<$Matches['groups']>>
: undefined
}
& (
$Matches extends { indicies: readonly [MatchItem, ...readonly MatchItem[]] }
? [originalValue: string, ...$Matches['indicies']]
: [originalValue: string]
)
[T]
Matches
type Matches = {
groups?: (string | undefined)[]
indicies?: (string | undefined)[]
}
[U]
PatternInput
type PatternInput = string | RegExp
[T]
PatternsInput
type PatternsInput = ArrMut.Maybe<string | RegExp>