Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

String

Works with TypeScript string values.

This module exposes common string operations in a pipe-friendly style. The helpers cover checks, comparison, concatenation, trimming, casing, slicing, padding, replacement, normalization, safe character access, search helpers that return Option, and joining strings through a reducer.

64 exports Since v2.0.0 Source

Combining

Since v2.0.0

Concatenates two strings at runtime.

Signature

declare const concat: {
<B extends string>(that: B): <A extends string>(self: A) => `${A}${B}`;
<A extends string, B extends string>(self: A, that: B): `${A}${B}`;
}

Example Concatenating strings

import { pipe, String } from "effect"
String.concat("hello", "world") // => "helloworld"
pipe("hello", String.concat("world")) // => "helloworld"

Reducer for concatenating strings.

When to use

Use to concatenate many strings through APIs that consume a Reducer.

Details

The reducer starts from "", so combining an empty collection returns "".

See

  • concat for concatenating two strings directly

Signature

declare const ReducerConcat: Reducer.Reducer<string>

Comparisons

Computes locale-aware ordering for two strings, with optional locales and collator options, and returns the result as an Ordering (-1, 0, or 1).

Signature

declare function localeCompare(that: string, locales?: Array<string>, options?: CollatorOptions): (self: string) => Ordering

Example Comparing strings by locale

import { pipe, String } from "effect"
pipe("a", String.localeCompare("b")) // => -1
pipe("b", String.localeCompare("a")) // => 1
pipe("a", String.localeCompare("a")) // => 0

Constants

Since v2.0.0

Provides the empty string "".

When to use

Use when you need the canonical empty string value from the String module.

Signature

declare const empty: ""

Example Referencing the empty string

import { String } from "effect"
String.empty // => ""
String.isEmpty(String.empty) // => true

Constructors

Since v4.0.0

Exposes the global string constructor.

When to use

Use to access native JavaScript string coercion or constructor behavior from the Effect module namespace.

Gotchas

Calling String(value) returns a primitive string. Calling new String(value) creates a boxed String object.

See

  • isString for checking whether a value is a primitive string

Signature

declare const String: StringConstructor

Getters

Since v2.0.0

Returns the character at the specified relative index safely, or None if the index is out of bounds.

Signature

declare const at: {
(index: number): (self: string) => Option<string>;
(self: string, index: number): Option<string>;
}

Example Accessing characters safely

import { Option, pipe, String } from "effect"
pipe("abc", String.at(1)) // => Option.some("b")
pipe("abc", String.at(4)) // => Option.none()
Since v2.0.0

Returns the character at the specified non-negative index safely, or None if the index is out of bounds.

Signature

declare const charAt: {
(index: number): (self: string) => Option<string>;
(self: string, index: number): Option<string>;
}

Example Reading characters safely

import { Option, pipe, String } from "effect"
pipe("abc", String.charAt(1)) // => Option.some("b")
pipe("abc", String.charAt(4)) // => Option.none()

Returns the character code at the specified index safely, or None if the index is out of bounds.

Signature

declare const charCodeAt: {
(index: number): (self: string) => Option<number>;
(self: string, index: number): Option<number>;
}

Example Reading character codes

import { Option, String } from "effect"
String.charCodeAt("abc", 1) // => Option.some(98)
String.charCodeAt("abc", 4) // => Option.none()

Returns the Unicode code point at the specified index safely, or None if the index is out of bounds.

Signature

declare const codePointAt: {
(index: number): (self: string) => Option<number>;
(self: string, index: number): Option<number>;
}

Example Reading code points

import { Option, pipe, String } from "effect"
pipe("abc", String.codePointAt(1)) // => Option.some(98)
pipe("abc", String.codePointAt(10)) // => Option.none()
Since v2.0.0

Returns the JavaScript string length, measured in UTF-16 code units.

Signature

declare function length(self: string): number

Example Getting string length

import { String } from "effect"
String.length("abc") // => 3

Guards

Since v2.0.0

Checks whether a string is empty.

Signature

declare function isEmpty(self: string): self is ""

Example Checking for empty strings

import { String } from "effect"
String.isEmpty("") // => true
String.isEmpty("a") // => false
Since v2.0.0

Checks whether a value is a string.

Signature

declare const isString: Refinement<unknown, string>

Example Checking for strings

import { String } from "effect"
String.isString("a") // => true
String.isString(1) // => false

Instances

Provides an Equivalence instance for strings using strict equality (===).

Signature

declare const Equivalence: Equ.Equivalence<string>

Example Comparing strings for equality

import { String } from "effect"
String.Equivalence("hello", "hello") // => true
String.Equivalence("hello", "world") // => false
Since v2.0.0

Provides an Order instance for comparing strings using lexicographic ordering.

Signature

declare const Order: order.Order<string>

Example Comparing strings lexicographically

import { String } from "effect"
String.Order("apple", "banana") // => -1
String.Order("banana", "apple") // => 1
String.Order("apple", "apple") // => 0

Models

Since v2.0.0

Concatenates two strings at the type level.

Signature

type Concat<A extends string, B extends string> = `${A}${B}`

Example Concatenating string literal types

import type { String } from "effect"
// Type-level concatenation
type Result = String.Concat<"hello", "world"> // "helloworld"
const witness: Result = "helloworld"

Trim

type
Since v2.0.0

Type-level representation of trimming whitespace from both ends of a string.

Signature

type Trim<A extends string> = TrimEnd<TrimStart<A>>

Example Trimming whitespace at the type level

import type { String } from "effect"
type Result = String.Trim<" hello "> // "hello"
const witness: Result = "hello"
Since v2.0.0

Type-level representation of trimming whitespace from the end of a string.

Signature

type TrimEnd<A extends string> = A extends `${infer B}${" " | "\n" | "\t" | "\r"}` ? TrimEnd<B> : A

Example Trimming trailing whitespace at the type level

import type { String } from "effect"
type Result = String.TrimEnd<"hello "> // "hello"
const witness: Result = "hello"
Since v2.0.0

Type-level representation of trimming whitespace from the start of a string.

Signature

type TrimStart<A extends string> = A extends `${" " | "\n" | "\t" | "\r"}${infer B}` ? TrimStart<B> : A

Example Trimming leading whitespace at the type level

import type { String } from "effect"
type Result = String.TrimStart<" hello"> // "hello"
const witness: Result = "hello"

Predicates

Since v2.0.0

Returns true if the string ends with the specified search string.

Signature

declare function endsWith(searchString: string, position?: number): (self: string) => boolean

Example Checking string suffixes

import { pipe, String } from "effect"
pipe("hello world", String.endsWith("world")) // => true
pipe("hello world", String.endsWith("hello")) // => false
Since v2.0.0

Returns true if searchString appears as a substring of self, at one or more positions that are greater than or equal to position; otherwise, returns false.

Signature

declare function includes(searchString: string, position?: number): (self: string) => boolean

Example Checking for substrings

import { pipe, String } from "effect"
pipe("hello world", String.includes("world")) // => true
pipe("hello world", String.includes("foo")) // => false

Checks whether a string is non-empty.

Signature

declare function isNonEmpty(self: string): boolean

Example Checking for non-empty strings

import { String } from "effect"
String.isNonEmpty("") // => false
String.isNonEmpty("a") // => true

Returns true if the string starts with the specified search string.

Signature

declare function startsWith(searchString: string, position?: number): (self: string) => boolean

Example Checking string prefixes

import { pipe, String } from "effect"
pipe("hello world", String.startsWith("hello")) // => true
pipe("hello world", String.startsWith("world")) // => false

Searching

Since v2.0.0

Returns the index of the first occurrence of a substring safely, or None if not found.

Signature

declare function indexOf(searchString: string): (self: string) => Option<number>

Example Finding the first substring index

import { Option, pipe, String } from "effect"
pipe("abbbc", String.indexOf("b")) // => Option.some(1)
pipe("abbbc", String.indexOf("z")) // => Option.none()

Returns the index of the last occurrence of a substring safely, or None if not found.

Signature

declare function lastIndexOf(searchString: string): (self: string) => Option<number>

Example Finding the last substring index

import { Option, pipe, String } from "effect"
pipe("abbbc", String.lastIndexOf("b")) // => Option.some(3)
pipe("abbbc", String.lastIndexOf("d")) // => Option.none()
Since v2.0.0

Matches a string against a pattern safely and returns Option.some with the match array, or Option.none when the pattern does not match.

Signature

declare function match(regExp: string | RegExp): (self: string) => Option<RegExpMatchArray>

Example Matching regular expressions

import { Option, pipe, String } from "effect"
pipe(
"hello",
String.match(/l+/),
Option.map((match) => [match[0], match.index])
) // => Option.some(["ll", 2])
pipe("hello", String.match(/x/)) // => Option.none()
Since v2.0.0

Returns an iterator over all regular expression matches in the string using native String.prototype.matchAll semantics.

Signature

declare function matchAll(regExp: RegExp): (self: string) => IterableIterator<RegExpMatchArray>

Example Iterating regular expression matches

import { pipe, String } from "effect"
const matches = pipe("hello world", String.matchAll(/l/g))
Array.from(matches, (match) => [match[0], match.index]) // => [["l", 2], ["l", 3], ["l", 9]]

Splitting

Returns an IterableIterator which yields each line contained within the string, trimming off the trailing newline character.

Signature

declare function linesIterator(self: string): LinesIterator

Example Iterating lines without separators

import { String } from "effect"
Array.from(String.linesIterator("hello\nworld\n")) // => ["hello", "world"]

Returns an IterableIterator which yields each line contained within the string as well as the trailing newline character.

Signature

declare function linesWithSeparators(s: string): LinesIterator

Example Iterating lines with separators

import { String } from "effect"
Array.from(String.linesWithSeparators("hello\nworld\n")) // => ["hello\n", "world\n"]

Transforming

Converts a string to camelCase.

When to use

Use to normalize mixed word separators or existing PascalCase/camelCase text into lower-initial camelCase identifiers.

See

  • noCase for configurable delimiters and part transforms
  • pascalCase for upper-initial PascalCase output
  • snakeCase for lowercase underscore-separated output
  • kebabCase for lowercase hyphen-separated output
  • constantCase for uppercase underscore-separated output

Signature

declare const camelCase: (self: string) => string

Converts a camelCase string to snake_case.

Signature

declare function camelToSnake(self: string): string

Example Converting camelCase to snake_case

import { String } from "effect"
String.camelToSnake("helloWorld") // => "hello_world"
String.camelToSnake("fooBarBaz") // => "foo_bar_baz"

Capitalizes the first character of a string.

Signature

declare function capitalize<T extends string>(self: T): Capitalize<T>

Example Capitalizing a string

import { pipe, String } from "effect"
pipe("abc", String.capitalize) // => "Abc"
String.capitalize("hello") // => "Hello"

Converts a string to CONFIG_CASE (uppercase with underscores) for configuration keys.

When to use

Use to normalize configuration path segments into environment-variable-like keys while preserving numeric word groups such as v2.

Details

Unlike constantCase, digit-letter boundaries are not split. For example, "api-v2 xml" becomes "API_V2_XML".

See

  • constantCase for standard uppercase underscore-separated output

Signature

declare const configCase: (self: string) => string

Converts a string to CONSTANT_CASE (uppercase with underscores).

When to use

Use to normalize words from mixed input formats into uppercase, underscore-separated identifiers.

See

  • snakeCase for lowercase underscore-separated output
  • kebabCase for lowercase hyphen-separated output
  • camelCase for lower-initial camelCase output
  • pascalCase for upper-initial PascalCase output
  • configCase for configuration key casing that preserves numeric word groups
  • noCase for configurable delimiters and part transforms

Signature

declare const constantCase: (self: string) => string

Converts a string to kebab-case (lowercase with hyphens).

When to use

Use to normalize free-form labels, identifiers, or keys into lowercase hyphen-separated text.

See

  • noCase for configurable delimiters and part transforms
  • snakeCase for lowercase underscore-separated output
  • constantCase for uppercase underscore-separated output
  • camelCase for lower-initial camelCase output
  • pascalCase for upper-initial PascalCase output

Signature

declare const kebabCase: (self: string) => string

Converts a kebab-case string to snake_case.

Signature

declare function kebabToSnake(self: string): string

Example Converting kebab-case to snake_case

import { String } from "effect"
String.kebabToSnake("hello-world") // => "hello_world"
String.kebabToSnake("foo-bar-baz") // => "foo_bar_baz"
Since v4.0.0

Normalizes a string by splitting it into word parts, transforming each part, and joining the parts with a configurable delimiter.

When to use

Use when you need custom word-case output with a delimiter or part transform that the fixed case helpers do not provide.

See

  • pascalCase for fixed PascalCase output
  • camelCase for fixed lower-initial camelCase output
  • constantCase for fixed uppercase underscore-separated output
  • kebabCase for fixed lowercase hyphen-separated output
  • snakeCase for fixed lowercase underscore-separated output

Signature

declare const noCase: {
(options?: {
readonly delimiter?: string;
readonly splitRegExp?: RegExp | ReadonlyArray<RegExp>;
readonly stripRegExp?: RegExp | ReadonlyArray<RegExp>;
readonly transform?: (part: string, index: number, parts: ReadonlyArray<string>) => string;
}): (self: string) => string;
(self: string, options?: {
readonly delimiter?: string;
readonly splitRegExp?: RegExp | ReadonlyArray<RegExp>;
readonly stripRegExp?: RegExp | ReadonlyArray<RegExp>;
readonly transform?: (part: string, index: number, parts: ReadonlyArray<string>) => string;
}): string;
}

Normalizes a string according to the specified Unicode normalization form.

Signature

declare function normalize(form?: "NFC" | "NFD" | "NFKC" | "NFKD"): (self: string) => string

Example Normalizing Unicode strings

import { pipe, String } from "effect"
const str = "\u1E9B\u0323"
Array.from(pipe(str, String.normalize()), (character) => character.codePointAt(0)) // => [0x1e9b, 0x323]
Array.from(pipe(str, String.normalize("NFC")), (character) => character.codePointAt(0)) // => [0x1e9b, 0x323]
Array.from(
pipe(str, String.normalize("NFD")),
(character) => character.codePointAt(0)
) // => [0x17f, 0x323, 0x307]
Array.from(pipe(str, String.normalize("NFKC")), (character) => character.codePointAt(0)) // => [0x1e69]
Array.from(
pipe(str, String.normalize("NFKD")),
(character) => character.codePointAt(0)
) // => [0x73, 0x323, 0x307]
Since v2.0.0

Pads the string from the end with a given fill string to a specified length.

Signature

declare function padEnd(maxLength: number, fillString?: string): (self: string) => string

Example Padding strings at the end

import { pipe, String } from "effect"
pipe("a", String.padEnd(5)) // => "a "
pipe("a", String.padEnd(5, "_")) // => "a____"
Since v2.0.0

Pads the string from the start with a given fill string to a specified length.

Signature

declare function padStart(maxLength: number, fillString?: string): (self: string) => string

Example Padding strings at the start

import { pipe, String } from "effect"
pipe("a", String.padStart(5)) // => " a"
pipe("a", String.padStart(5, "_")) // => "____a"

Converts a string to PascalCase.

When to use

Use to normalize strings from spaces, separators, or camel/Pascal word boundaries into PascalCase.

See

  • camelCase for lower-initial camelCase output
  • noCase for configurable delimiters and part transforms
  • snakeToPascal for converting known snake_case input only

Signature

declare const pascalCase: (self: string) => string

Converts a PascalCase string to snake_case.

Signature

declare function pascalToSnake(self: string): string

Example Converting PascalCase to snake_case

import { String } from "effect"
String.pascalToSnake("HelloWorld") // => "hello_world"
String.pascalToSnake("FooBarBaz") // => "foo_bar_baz"
Since v2.0.0

Repeats the string the specified number of times.

Details

count is rounded down. NaN and non-positive values are treated as 0.

Signature

declare function repeat(count: number): (self: string) => string

Example Repeating strings

import { pipe, String } from "effect"
pipe("a", String.repeat(5)) // => "aaaaa"
pipe("hello", String.repeat(3)) // => "hellohellohello"
Since v2.0.0

Replaces matches in a string using String.prototype.replace.

Details

String search values and non-global regular expressions replace the first match; global regular expressions replace every match.

Signature

declare function replace(searchValue: string | RegExp, replaceValue: string): (self: string) => string

Example Replacing a substring

import { pipe, String } from "effect"
pipe("abc", String.replace("b", "d")) // => "adc"
pipe("hello world", String.replace("world", "Effect")) // => "hello Effect"

Replaces all occurrences of a substring or pattern in a string.

Signature

declare function replaceAll(searchValue: string | RegExp, replaceValue: string): (self: string) => string

Example Replacing all matches

import { pipe, String } from "effect"
pipe("ababb", String.replaceAll("b", "c")) // => "acacc"
pipe("ababb", String.replaceAll(/ba/g, "cc")) // => "accbb"
Since v2.0.0

Extracts a section of a string and returns it as a new string.

Signature

declare function slice(start?: number, end?: number): (self: string) => string

Example Slicing strings

import { pipe, String } from "effect"
pipe("abcd", String.slice(1, 3)) // => "bc"
pipe("hello world", String.slice(0, 5)) // => "hello"

Converts a string to snake_case (lowercase with underscores).

When to use

Use to normalize mixed-case or separator-delimited text into lowercase words joined with underscores.

See

  • noCase for configurable lower-level normalization
  • kebabCase for lowercase hyphen-separated output
  • constantCase for uppercase underscore-separated output

Signature

declare const snakeCase: (self: string) => string

Converts a snake_case string to camelCase.

Signature

declare function snakeToCamel(self: string): string

Example Converting snake_case to camelCase

import { String } from "effect"
String.snakeToCamel("hello_world") // => "helloWorld"
String.snakeToCamel("foo_bar_baz") // => "fooBarBaz"

Converts a snake_case string to kebab-case.

Signature

declare function snakeToKebab(self: string): string

Example Converting snake_case to kebab-case

import { String } from "effect"
String.snakeToKebab("hello_world") // => "hello-world"
String.snakeToKebab("foo_bar_baz") // => "foo-bar-baz"

Converts a snake_case string to PascalCase.

Signature

declare function snakeToPascal(self: string): string

Example Converting snake_case to PascalCase

import { String } from "effect"
String.snakeToPascal("hello_world") // => "HelloWorld"
String.snakeToPascal("foo_bar_baz") // => "FooBarBaz"
Since v2.0.0

Splits a string into an array of substrings using a separator.

Signature

declare const split: {
(separator: string | RegExp): (self: string) => [string, ...Array<string>];
(self: string, separator: string | RegExp): [string, ...Array<string>];
}

Example Splitting strings

import { pipe, String } from "effect"
pipe("abc", String.split("")) // => ["a", "b", "c"]
pipe("", String.split("")) // => [""]
String.split("hello,world", ",") // => ["hello", "world"]

Strips a leading | margin prefix from every line.

Signature

declare function stripMargin(self: string): string

Example Stripping pipe margins

import { String } from "effect"
String.stripMargin(" |hello\n |world") // => "hello\nworld"

Strips a leading margin prefix from every line using the supplied margin character.

Signature

declare const stripMarginWith: {
(marginChar: string): (self: string) => string;
(self: string, marginChar: string): string;
}

Example Stripping custom margins

import { String } from "effect"
String.stripMarginWith(" |hello\n |world", "|") // => "hello\nworld"

Extracts characters from a string between two specified indices.

Signature

declare function substring(start: number, end?: number): (self: string) => string

Example Extracting substrings

import { pipe, String } from "effect"
pipe("abcd", String.substring(1)) // => "bcd"
pipe("abcd", String.substring(1, 3)) // => "bc"
Since v2.0.0

Keeps the specified number of characters from the start of a string.

Details

If n is larger than the available number of characters, the string will be returned whole.

If n is not a positive number, including NaN, an empty string will be returned.

If n is a float, it will be rounded down to the nearest integer.

Signature

declare const takeLeft: {
(n: number): (self: string) => string;
(self: string, n: number): string;
}

Example Taking characters from the start

import { String } from "effect"
String.takeLeft("Hello World", 5) // => "Hello"

Keeps the specified number of characters from the end of a string.

Details

If n is larger than the available number of characters, the string will be returned whole.

If n is not a positive number, including NaN, an empty string will be returned.

If n is a float, it will be rounded down to the nearest integer.

Signature

declare const takeRight: {
(n: number): (self: string) => string;
(self: string, n: number): string;
}

Example Taking characters from the end

import { String } from "effect"
String.takeRight("Hello World", 5) // => "World"

Converts the string to lowercase according to the specified locale.

Signature

declare function toLocaleLowerCase(locale?: string | Array<string>): (self: string) => string

Example Lowercasing strings by locale

import { pipe, String } from "effect"
const str = "\u0130"
pipe(str, String.toLocaleLowerCase("tr")) // => "i"

Converts the string to uppercase according to the specified locale.

Signature

declare function toLocaleUpperCase(locale?: string | Array<string>): (self: string) => string

Example Uppercasing strings by locale

import { pipe, String } from "effect"
const str = "i\u0307"
pipe(str, String.toLocaleUpperCase("lt-LT")) // => "I"

Converts a string to lowercase.

Signature

declare function toLowerCase<T extends string>(self: T): Lowercase<T>

Example Converting strings to lowercase

import { pipe, String } from "effect"
pipe("A", String.toLowerCase) // => "a"
String.toLowerCase("HELLO") // => "hello"

Converts a string to uppercase.

Signature

declare function toUpperCase<S extends string>(self: S): Uppercase<S>

Example Converting strings to uppercase

import { pipe, String } from "effect"
pipe("a", String.toUpperCase) // => "A"
String.toUpperCase("hello") // => "HELLO"
Since v2.0.0

Removes whitespace from both ends of a string.

Signature

declare function trim<A extends string>(self: A): TrimEnd<TrimStart<A>>

Example Trimming whitespace

import { String } from "effect"
String.trim(" a ") // => "a"
String.trim(" hello world ") // => "hello world"
Since v2.0.0

Removes whitespace from the end of a string.

Signature

declare function trimEnd<A extends string>(self: A): TrimEnd<A>

Example Trimming trailing whitespace

import { String } from "effect"
String.trimEnd(" a ") // => " a"
String.trimEnd("hello world ") // => "hello world"

Removes whitespace from the start of a string.

Signature

declare function trimStart<A extends string>(self: A): TrimStart<A>

Example Trimming leading whitespace

import { String } from "effect"
String.trimStart(" a ") // => "a "
String.trimStart(" hello world") // => "hello world"

Uncapitalizes the first character of a string.

Signature

declare function uncapitalize<T extends string>(self: T): Uncapitalize<T>

Example Uncapitalizing a string

import { pipe, String } from "effect"
pipe("ABC", String.uncapitalize) // => "aBC"
String.uncapitalize("Hello") // => "hello"