ZetCode

TypeScript Strings

last modified October 15, 2026

A string is a sequence of characters used to represent text. TypeScript strings are JavaScript strings: they are immutable, every method returns a new string, and the characters are stored as UTF-16 code units. The string type annotation ensures that only text is assigned to a variable and that only string methods are called on it.

Creating Strings

Strings can be written with double quotes, single quotes, or backticks. Backticks create template literals, which can contain embedded expressions and line breaks.

declaring_strings.ts
const greeting: string = "Welcome";
const filename: string = 'app.js';
const path: string = `C:/projects/${filename}`;
const quote = "She said \"hello\"";
const multiline = `line one
line two`;

console.log(greeting);
console.log(path);
console.log(quote);
console.log(multiline);

Double and single quotes are equivalent; a project usually picks one style. Inside quotes, special characters are escaped with a backslash, as in \". The template literal in path inserts the value of filename, and multiline keeps the line break. The type of all variables is string; the annotations can be left out, because the compiler infers them.

$ npx tsx declaring_strings.ts
Welcome
C:/projects/app.js
She said "hello"
line one
line two

Length and Characters

The length property returns the number of UTF-16 code units. Individual characters are read by index.

string_basics.ts
const word = "TypeScript";

console.log(word.length);
console.log(word[0], word[4]);
console.log(word.at(-1));
console.log(word[20]);

Indexes start at 0, so word[4] is the fifth character. The at method also accepts negative indexes, which count from the end. Reading an index past the end returns undefined; the compiler types word[20] as string unless the noUncheckedIndexedAccess option is enabled.

$ npx tsx string_basics.ts
10
T S
t
undefined

Strings Are Immutable

A character of a string cannot be changed. Methods that seem to modify a string return a new one.

immutable.ts
const word = "cat";

word[0] = "b";

TypeScript reports the assignment, because the index signature of strings is read-only. In plain JavaScript, the assignment would be silently ignored. To get "bat", a new string is built, for example with "b" + word.slice(1).

$ npx tsc --noEmit
immutable.ts(3,1): error TS2542: Index signature in type 'String' only permits reading.

String Methods

The String type has many methods for common text operations.

string_methods.ts
const message = "  TypeScript Essentials  ";
const text = message.trim();

console.log(`[${text}]`);
console.log(text.toUpperCase());
console.log(text.toLowerCase());
console.log(text.slice(4, 10));
console.log(text.startsWith("Type"), text.endsWith("ials"));
console.log("7".padStart(3, "0"), "ab".repeat(3));

The trim method removes whitespace from both ends; trimStart and trimEnd remove it from one side. slice(4, 10) returns the characters from index 4 up to, but not including, index 10. startsWith and endsWith test the beginning and the end. padStart fills a string to a given length, which is handy for numbers with leading zeros, and repeat concatenates copies of a string.

None of these methods changes message or text; each returns a new string.

$ npx tsx string_methods.ts
[TypeScript Essentials]
TYPESCRIPT ESSENTIALS
typescript essentials
Script
true true
007 ababab

Splitting and Joining

The split method divides a string into an array of parts; the join array method does the opposite.

split_join.ts
const csv = "apple,banana,cherry";

const fruits = csv.split(",");
console.log(fruits, fruits.length);

console.log(fruits.join(" | "));

const words = "  the quick   brown fox ".trim().split(/\s+/);
console.log(words);

const title = words.map(w => w[0].toUpperCase() + w.slice(1)).join(" ");
console.log(title);

The type of fruits is string[]. The separator can also be a regular expression: /\s+/ matches one or more whitespace characters, so multiple spaces between words do not produce empty strings. The last example capitalizes each word and joins the words back into a string.

$ npx tsx split_join.ts
[ 'apple', 'banana', 'cherry' ] 3
apple | banana | cherry
[ 'the', 'quick', 'brown', 'fox' ]
The Quick Brown Fox

Searching and Replacing

Strings can be searched with methods that return a position or a boolean, and parts of them can be replaced.

search_replace.ts
const text = "The cat sat on the mat with another cat.";

console.log(text.includes("cat"));
console.log(text.indexOf("cat"), text.lastIndexOf("cat"));
console.log(text.indexOf("dog"));

console.log(text.replace("cat", "dog"));
console.log(text.replaceAll("cat", "dog"));
console.log(text.replace(/\b(\w)at\b/g, "[$1at]"));

The indexOf method returns the position of the first match or -1 if there is none. The replace method with a string pattern replaces only the first occurrence; replaceAll replaces all of them. With a regular expression and the g flag, replace also replaces all matches, and $1 refers to the first captured group. The last line marks every three-letter word ending in at.

$ npx tsx search_replace.ts
true
4 36
-1
The dog sat on the mat with another cat.
The dog sat on the mat with another dog.
The [cat] [sat] on the [mat] with another [cat].

String Interpolation

Template literals evaluate the expressions inside ${...} and insert their values into the string.

string_interpolation.ts
const user = "Alice";
const tasks: number = 5;
const done: number = 3;

console.log(`${user} has ${tasks} pending tasks`);
console.log(`${user} finished ${Math.round((done / tasks) * 100)}% of her work`);
console.log(`Status: ${done === tasks ? "complete" : "in progress"}`);

Any expression can appear inside the placeholders: variables, arithmetic, function calls, or conditional expressions. Values that are not strings are converted automatically. Template literals are easier to read than chains of + operators.

$ npx tsx string_interpolation.ts
Alice has 5 pending tasks
Alice finished 60% of her work
Status: in progress

String Validation

Simple checks can be done with string methods. For patterns, regular expressions are more precise.

string_validation.ts
function isValidEmail(email: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function isValidUsername(name: string): boolean {
    const trimmed = name.trim();
    return trimmed.length >= 3 && trimmed.length <= 16 && /^[a-z0-9_]+$/i.test(trimmed);
}

console.log(isValidEmail("user@example.com"));
console.log(isValidEmail("invalid.email"));
console.log(isValidEmail("a@b"));

console.log(isValidUsername("jan_bodnar"));
console.log(isValidUsername("x"));

The regular expression in isValidEmail requires some characters, an @, a domain, a dot, and an ending, without spaces. It is a reasonable check for user input, not a full implementation of the e-mail standard. isValidUsername combines a length check with a pattern that allows only letters, digits, and underscores; the i flag makes the match case-insensitive.

$ npx tsx string_validation.ts
true
false
false
true
false

Iterating Over Strings

Strings are iterable, so the for...of loop visits one character at a time.

string_iteration.ts
const charset = "ABCD";

for (const char of charset) {
    console.log(char);
}

const emoji = "hi 👋";
console.log(emoji.length, [...emoji].length);

The for...of loop and the spread operator iterate over Unicode code points. This matters for characters outside the basic range, such as many emoji, which take two UTF-16 code units. The length of emoji is 5, but it has only 4 characters.

$ npx tsx string_iteration.ts
A
B
C
D
5 4

Comparing and Sorting Strings

Strings are compared with === for equality. For ordering, localeCompare follows the rules of a language.

compare_strings.ts
const a: string = "apple";
const b: string = "Apple";

console.log(a === b);
console.log(a.toLowerCase() === b.toLowerCase());

const names = ["Žofia", "zuzana", "Adam", "eva", "Ľubo"];

console.log([...names].sort());
console.log([...names].sort((x, y) => x.localeCompare(y, "sk")));

Equality is case-sensitive, so a case-insensitive comparison converts both strings first. The variables are annotated as string: without the annotations, their types would be the literals "apple" and "Apple", and the compiler would report the comparison as always false. The default sort orders strings by their UTF-16 code units: all uppercase letters come before lowercase ones, and accented letters end up at the end. localeCompare with the "sk" locale sorts the names as a Slovak reader expects.

$ npx tsx compare_strings.ts
false
true
[ 'Adam', 'eva', 'zuzana', 'Ľubo', 'Žofia' ]
[ 'Adam', 'eva', 'Ľubo', 'zuzana', 'Žofia' ]

String Literal Types

TypeScript can restrict a string to specific values with literal types. Template literal types build such types from other strings.

literal_types.ts
type Direction = "left" | "right" | "up" | "down";
type Size = "small" | "large";
type Color = "red" | "blue";
type Variant = `${Size}-${Color}`;

function move(direction: Direction, steps: number): string {
    return `moving ${direction} by ${steps}`;
}

const variant: Variant = "large-red";

console.log(move("left", 3));
console.log(variant);

Calling move("forward", 3) would not compile, because "forward" is not a Direction. The Variant type combines the two unions into all four possible strings: "small-red", "small-blue", "large-red", and "large-blue".

$ npx tsx literal_types.ts
moving left by 3
large-red

Best Practices

Source

MDN: String

This tutorial covered strings in TypeScript. String values and methods come from JavaScript; TypeScript adds the string type, checks method calls, and offers string literal types for fixed sets of values.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all TypeScript tutorials.