Start learning free

LESSON 170 OF 348 · STRINGS

Strings in TypeScript: Slicing, Splitting and Immutability

Lesson Read the full explanation

The JavaScript string is an object that represents a sequence of characters, each identified by one index.

Creation:

To create strings in JavaScript, you use either single quotes or double quotes like this:

let str = 'Hi';
let greeting = "Hello";

'Hi' and "Hello" are called a string literals. A string literal, or string, is a series of zero or more characters enclosed in single or double quotes.

Accessing characters:

To access the characters in a string, you use the array-like [] notation with the zero-based index.

The following example returns the first character of a string with the index zero:

let str = "Hello";
console.log(str[0]); // "H"

Getting the length:

We can get the length of a string using the .length property.

For example, to access the last character of the string, you use the length - 1 index:

let str = "Hello";
console.log(str[str.length - 1]); // "o"

Concatenating strings via + operator:

To concatenate two or more strings, you use the + operator:

let name = 'John';
let str = 'Hello ' + name;

console.log(str); // "Hello John"

If you want to assemble a string piece by piece, you can use the += operator:

let greet = 'Welcome';
let name = 'John';
greet += ' to AlgoCademy, ';
greet += name;

console.log(greet); // "Welcome to AlgoCademy, John"

String slicing

We often want to get a substring of a string. For this, we use the slice() method.

slice(startIndex, endIndex) returns the substring from startIndex to endIndex:

let str = 'JavaScript';
let substr = str.slice(2, 6);

console.log(substr); // "vaSc"

The startIndex is a zero-based index at which the slice() start extraction.

The endIndex is also zero-based index before which the slice() ends the extraction. The substr will not include the character at the endIndex index.

If you omit the endIndex, the slice() extracts to the end of the string:

let str = 'JavaScript';
let substr = str.slice(4);

console.log(substr); // "Script"

String Immutability:

In JavaScript, String values are immutable, which means that they cannot be altered once created.

For example, the following code:

let myStr = "Bob";
myStr[0] = 'J';

cannot change the value of myStr to "Job", because the contents of myStr cannot be altered.

Note that this does not mean that myStr cannot be changed, just that the individual characters of a string literal cannot be changed. The only way to change myStr would be to assign it with a new string, like this:

let myStr = "Bob";
myStr = "Job";
//or
myStr = 'J' + myStr.slice(1, 3);

The split function

The split() method splits (divides) a string into two or more substrings depending on a splitter (or divider). The splitter can be a single character, another string, or a regular expression.

After splitting the string into multiple substrings, the split() method puts them in an array and returns it. It doesn't make any modifications to the original string.

This splitter is provided as an argument in the split() function. For example:

let str = "I am happy!";
let myArr = str.split(" ");

console.log(myArr); // ['I', 'am', 'happy!']

Convert a string to an array of characters:

When we have to change characters often in a string, we want a way of doing this quickly. Because strings are immutable, we change a character by creating a whole new string, which is O(n).

But arrays are mutable and chaning an element in an array is O(1). So what we can do is first convert our string to an array of characters, operate on that array and than convert the array back to a string.

We can convert a string to an array using the split() method with an empty splitter (''), like this:

let str = "Andy";
let myArr = str.split('');

console.log(myArr); // ['A', 'n', 'd', 'y']
myArr[0] = 'a';
myArr[2] = 'D';

// We convert an array of chars to a string with join():
str = myArr.join('');

console.log(str); // "anDy"

Iterating through the characters:

We can iterate throught the characters of a string using a for loop and the of keyword like this:

var myStr = "Andy";
for (let c of myStr) {
    console.log(c);
}

// This will print the characters 'A', 'n', 'd' and 'y' on different lines

We can also iterate throught the elements of a string using indices and a for loop like this:

var myStr = "Andy";
for (let i = 0; i < myStr.length; i++) {
    console.log(myStr[i]);
}

// This will print the characters 'A', 'n', 'd' and 'y' on different lines

Both ways take O(n) time, where n is the length of the array we iterate on.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 7
    Ctrl + Enter to check

    TYPESCRIPT · STRINGS

    Strings in TypeScript, explained

    Strings are values that never change

    A TypeScript string is a sequence of characters, and each character has an index that starts at 0. You read a character with square brackets and ask for the size with .length:

    let str: string = "Hello";
    console.log(str[0]);              // H
    console.log(str[str.length - 1]); // o
    

    The key property of strings is that they are immutable. You can read a character, but you can't replace it. The compiler rejects str[0] = "J", and the string would not change even if the assignment ran. To get a different string, you build a new one and store it in the variable:

    let myStr: string = "Bob";
    myStr = "Job";
    myStr = "J" + myStr.slice(1, 3);
    console.log(myStr); // Job
    

    The variable is what changes: it now refers to a new string. This is why most of this lesson is about methods that return a new string or an array, instead of editing in place.

    Joining with + and +=

    The + operator joins two strings into a new one. The += operator joins and stores the result back in the variable, so it is the natural way to assemble a string piece by piece:

    let greet: string = "Welcome";
    greet += " to the course, ";
    greet += "Ana";
    console.log(greet); // Welcome to the course, Ana
    

    Each += doesn't append to the old string. It creates a new string from the old one plus the right side, and the variable then points to it.

    Slicing with slice

    slice(startIndex, endIndex) returns the part of the string from startIndex up to, but not including, endIndex. If you leave out the end, it goes to the end of the string:

    let word: string = "JavaScript";
    console.log(word.slice(2, 6)); // vaSc
    console.log(word.slice(4));    // Script
    

    The "up to but not including" rule is easy to forget. The length of the result is endIndex - startIndex, so slice(2, 6) returns 4 characters. An end index past the length is not an error: "abc".slice(1, 100) is "bc". A negative index counts from the end, so slice(-2) gives the last two characters.

    Splitting into an array

    split(separator) cuts a string at every occurrence of the separator and returns an array of the pieces. The original string is untouched:

    let sentence: string = "I am happy!";
    let parts: string[] = sentence.split(" ");
    console.log(parts); // [ 'I', 'am', 'happy!' ]
    

    Splitting on the empty string "" cuts between every pair of characters, which gives an array with one one-character string per element. Two edge cases are worth knowing: "a,b,,c".split(",") keeps the empty piece, giving ["a", "b", "", "c"], and "".split(" ") gives [""], an array with one empty string, not an empty array.

    Editing characters through an array

    Changing one character of a string means building a whole new string, which costs time proportional to its length. When you need many changes, it is cheaper to convert the string to an array of characters, change the array, and join it back. Arrays are mutable, and assigning to an element is a single step:

    let name1: string = "Andy";
    let chars: string[] = name1.split("");
    chars[0] = "a";
    chars[2] = "D";
    name1 = chars.join("");
    console.log(name1); // anDy
    

    join(separator) is the opposite of split. It glues the elements together with the separator between them, and join("") uses nothing at all. Leaving the argument out is a trap: join() uses a comma, so ["a", "b"].join() gives "a,b".

    One caution: split("") cuts between 16-bit units, not between visible characters. For letters and digits that is the same thing, but an emoji such as "😀" is cut into two broken halves.

    Looping over the characters

    You can loop with for...of, which gives each character, or with an index and length:

    const text: string = "Andy";
    for (const c of text) {
        console.log(c);
    }
    for (let i = 0; i < text.length; i++) {
        console.log(text[i]);
    }
    

    Both print A, n, d and y on separate lines and take time proportional to the length of the string.

    The lesson's exercise, step by step

    The exercise turns "Java" into "TypeScript" using the tools above.

    1. Create lang, annotated as string, holding "Java". It is declared with let because the next step reassigns it.
    2. Append with +=. Adding "script" makes lang hold "Javascript". The old string isn't edited: a new one is built and stored back.
    3. Take the tail with slice(4). The first four characters, Java, sit at indexes 0 to 3, so index 4 starts script. The result goes in substr.
    4. Build newLang as "Type" plus substr. That gives "Typescript", with a lowercase s.
    5. Make a mutable copy. Strings can't be edited, so charArray, a string[], gets newLang.split("").
    6. Capitalize the s. It is the fifth character, so it sits at index 4. Assign "S" to charArray[4].
    7. Join back. charArray.join("") builds the final string, and assigning it to newLang makes it "TypeScript".
    let lang: string = "Java";
    lang += "script";
    let substr: string = lang.slice(4);
    let newLang: string = "Type" + substr;
    let charArray: string[] = newLang.split("");
    charArray[4] = "S";
    newLang = charArray.join("");
    

    After the last line, newLang is "TypeScript". If you print lang and substr along the way, you see Javascript and script.

    Common mistakes

    • Expecting a method to change the string. str.slice(1) on its own line does nothing useful. Its result is lost unless you store it.
    • Off-by-one in slice. The end index is excluded, and the first index is 0.
    • Using const and then reassigning. += assigns, so the variable must be declared with let.
    • Forgetting the type on the array. split returns string[], and each element is a string, even for digits.
    • Skipping join. An array is not a string. Printing or comparing the array instead of the joined result gives something you didn't expect.

    Key takeaways

    • Strings are immutable: you replace the whole value, not a character.
    • += builds a new string and stores it back in the variable.
    • slice(start, end) excludes end, and slice(start) runs to the end.
    • split("") and join("") let you edit characters through an array and then rebuild the string.
    Keep going with TypeScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free