Start learning free

LESSON 67 OF 348 · STRINGS I

String Find in TypeScript: indexOf and lastIndexOf

Lesson Read the full explanation

In JavaScript, you can find the index of a substring using indexOf():

s.indexOf(sub)         // returns index of first occurrence, or -1 if not found
s.lastIndexOf(sub)     // returns index of last occurrence
s.indexOf(sub, start)  // search starting from index `start`

Here are some examples:

let sentence = "Hello World";
let idx = sentence.indexOf("World");
console.log(idx);  // 6

console.log(sentence.indexOf("xyz"));  // -1  (not found)

The index returned is the position of the first character of the found substring.


Assignment
Follow the Coding Tutorial and find the index of "World" in sentence!


Hint
Use sentence.indexOf("World") and assign the result to idx.

STEP 1 OF 1
    Ctrl + Enter to check

    TYPESCRIPT · STRINGS I

    String Find in TypeScript, explained

    Finding text inside a string

    Often you need to know where a piece of text sits inside a longer string, or whether it is there at all. TypeScript strings are JavaScript strings, so they come with the indexOf method for this:

    s.indexOf(sub)         // index of the first occurrence, or -1 if not found
    s.lastIndexOf(sub)     // index of the last occurrence, or -1
    s.indexOf(sub, start)  // start searching at index start
    

    The result is a number. When the substring is found, it is the index of its first character. When it isn't found, the result is -1, which can never be a real index.

    const sentence: string = "Hello World";
    
    console.log(sentence.indexOf("World")); // 6
    console.log(sentence.indexOf("o"));     // 4
    console.log(sentence.indexOf("xyz"));   // -1
    

    "World" starts at index 6 because H e l l o takes indexes 0 to 4, the space is index 5, and the W is index 6. The call sentence.indexOf("o") returns 4, the first o, even though a second one appears later.

    Last occurrence and a starting point

    lastIndexOf scans from the end and returns the position of the last match. The second argument of indexOf says where to begin, which lets you skip past a match you already have:

    const sentence: string = "Hello World";
    
    console.log(sentence.lastIndexOf("o"));  // 7
    console.log(sentence.indexOf("o", 5));   // 7
    

    Calling indexOf("o", 5) ignores everything before index 5, so it skips the o in "Hello" and finds the one in "World". To visit every match, search again starting one past the previous result.

    The exercise

    The starting code defines the string:

    const sentence: string = "Hello World";
    

    The task is to store the index where "World" begins in a new variable named idx, with the type number.

    1. Write a const declaration below sentence, named idx, with the annotation : number.
    2. Call indexOf on sentence and pass "World".
    3. Assign that result to idx.

    The finished code:

    const sentence: string = "Hello World";
    
    const idx: number = sentence.indexOf("World");
    

    Here idx holds 6. The method only reads the string, so sentence itself doesn't change.

    Gotchas

    • The search is case-sensitive. sentence.indexOf("world") returns -1, because the lowercase w doesn't match the capital one. To ignore case, convert both sides with toLowerCase() first.
    • Index 0 is a valid result, but it is falsy. if (sentence.indexOf("Hello")) doesn't run its block, because the result is 0, which counts as false. Compare explicitly: sentence.indexOf("Hello") !== -1. Or use includes, which answers a yes or no question:
    const sentence: string = "Hello World";
    
    console.log(sentence.indexOf("Hello") !== -1); // true
    console.log(sentence.includes("Hello"));       // true
    console.log(sentence.includes("xyz"));         // false
    
    • Don't use -1 as an index. If the text may be missing, check the result before using it. sentence[sentence.indexOf("xyz")] reads sentence[-1], which is undefined.
    • An empty substring matches immediately. sentence.indexOf("") returns 0.
    • It finds text, not patterns. The argument is plain text. The method doesn't understand wildcards or regular expressions; for those, search or match are the tools.

    Putting indexOf to work

    The result of indexOf is usually a stepping stone to something else, such as cutting a string at a known point. Here the position of @ splits an address into two parts:

    const email: string = "ana@example.com";
    const at: number = email.indexOf("@");
    
    console.log(email.slice(0, at));     // ana
    console.log(email.slice(at + 1));    // example.com
    

    The start argument also lets you count every match. After each hit, search again from one position later, and stop when the result is -1:

    const text: string = "one fish, two fish, red fish";
    let pos: number = text.indexOf("fish");
    let count: number = 0;
    
    while (pos !== -1) {
        count++;
        pos = text.indexOf("fish", pos + 1);
    }
    console.log(count); // 3
    

    The matches sit at indexes 4, 14 and 24. Without the + 1, the loop would find the same match again and never finish.

    Choosing the right tool

    Pick the method that matches the question you are asking. If you need the position, use indexOf. If you only need to know whether the text occurs, includes reads better and avoids the -1 comparison. If you need to know whether a string begins or ends with some text, startsWith and endsWith say so directly. All of them are case-sensitive and all of them leave the original string unchanged.

    Key takeaways

    • indexOf returns the index of the first match, or -1 when there is none.
    • lastIndexOf returns the last match, and a second argument to indexOf sets where the search starts.
    • The search is case-sensitive, and the result 0 is a real match.
    • Test with !== -1 or use includes when you only need to know whether the text is present.
    Keep going with TypeScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free