Strings
Introductionβ
Strings are sequences of characters that represent text . They're one of the most fundamental and frequently used data types in programming. Whether you're displaying messages to users, processing form input, working with file names, or handling data from APIs, you're working with strings.
In TypeScript, strings have the same powerful methods as JavaScript, but with the added benefit of type safety . TypeScript ensures you're calling the right methods and passing the correct types of arguments, preventing common string-related bugs.
Why Strings Matterβ
Think about all the text in a program:
- User names and messages
- Error messages and notifications
- File paths and URLs
- Email addresses and phone numbers
- Product descriptions and reviews
- Search queries and filters
Strings are everywhere! Mastering string manipulation is essential for any developer.
TypeScript's String Type Safetyβ
JavaScript (no type checking):
function greet(name) {
return name.toUpperCase(); // What if name is not a string?
}
greet("Alice"); // β
"ALICE"
greet(123); // π₯ Runtime error: toUpperCase is not a function
TypeScript (with type checking):
function greet(name: string): string {
return name.toUpperCase();
}
greet("Alice"); // β
"ALICE"
// greet(123); // β Compile error: Argument of type 'number' is not assignable
Strings Are Immutableβ
An important concept: strings cannot be changed after they're created . Instead, string methods create and return new strings :
let original: string = "Hello";
let modified: string = original.toUpperCase();
console.log(original); // "Hello" - unchanged!
console.log(modified); // "HELLO" - new string
// This doesn't change the string:
original[0] = "J";
console.log(original); // Still "Hello" (not "Jello")
Creating Stringsβ
TypeScript supports three ways to create strings:
Single Quotesβ
let greeting: string = 'Hello, World!';
let message: string = 'It\'s a beautiful day'; // Escape single quote with \
Double Quotesβ
let greeting: string = "Hello, World!";
let message: string = "She said \"Hello\""; // Escape double quote with \
Template Literals (Backticks)β
The most powerful way - supports interpolation and multiline strings:
let name: string = "Alice";
let age: number = 25;
// String interpolation
let message: string = `Hello, ${name}! You are ${age} years old.`;
console.log(message); // "Hello, Alice! You are 25 years old."
// Expressions inside ${}
let calculation: string = `5 + 3 = ${5 + 3}`;
console.log(calculation); // "5 + 3 = 8"
// Multiline strings
let poem: string = `Roses are red,
Violets are blue,
TypeScript is awesome,
And so are you!`;
Which should you use?
- Use template literals (backticks) for most cases, especially with interpolation
- Single or double quotes are fine for simple strings without interpolation
- Be consistent within your codebase
String Propertiesβ
Length Propertyβ
Get the number of characters in a string:
let text: string = "Hello";
console.log(text.length); // 5
let empty: string = "";
console.log(empty.length); // 0
let sentence: string = "TypeScript is great!";
console.log(sentence.length); // 20
// Useful for validation
function isValidPassword(password: string): boolean {
return password.length >= 8;
}
console.log(isValidPassword("abc123")); // false
console.log(isValidPassword("abc12345")); // true
Note: Emojis and special characters can have unexpected lengths:
let emoji: string = "π";
console.log(emoji.length); // 2 (not 1!) - because of how Unicode works
let flag: string = "πΊπΈ";
console.log(flag.length); // 4 (flag emojis are actually two emojis combined)
String Methodsβ
Case Conversionβ
toUpperCase()β
Converts all characters to uppercase:
let text: string = "Hello World";
let upper: string = text.toUpperCase();
console.log(upper); // "HELLO WORLD"
// Useful for case-insensitive comparisons
function compareIgnoreCase(str1: string, str2: string): boolean {
return str1.toUpperCase() === str2.toUpperCase();
}
console.log(compareIgnoreCase("Hello", "HELLO")); // true
console.log(compareIgnoreCase("Hello", "Goodbye")); // false
toLowerCase()β
Converts all characters to lowercase:
let text: string = "Hello World";
let lower: string = text.toLowerCase();
console.log(lower); // "hello world"
// Normalize user input
function normalizeEmail(email: string): string {
return email.toLowerCase().trim();
}
console.log(normalizeEmail(" Alice@EMAIL.COM ")); // "alice@email.com"
Trimming Whitespaceβ
trim()β
Removes whitespace from both ends:
let messy: string = " Hello World ";
let clean: string = messy.trim();
console.log(clean); // "Hello World"
console.log(clean.length); // 11 (vs original 17)
// Cleaning user input
function sanitizeInput(input: string): string {
return input.trim();
}
console.log(sanitizeInput(" Alice ")); // "Alice"
trimStart() / trimEnd()β
Remove whitespace from one end only:
let text: string = " Hello World ";
console.log(text.trimStart()); // "Hello World "
console.log(text.trimEnd()); // " Hello World"
Searching Within Stringsβ
includes()β
Check if a string contains a substring:
let text: string = "Hello World";
console.log(text.includes("World")); // true
console.log(text.includes("world")); // false (case-sensitive!)
console.log(text.includes("Hello")); // true
console.log(text.includes("Goodbye")); // false
// Case-insensitive search
function containsIgnoreCase(text: string, search: string): boolean {
return text.toLowerCase().includes(search.toLowerCase());
}
console.log(containsIgnoreCase("Hello World", "world")); // true
startsWith() / endsWith()β
Check the beginning or end of a string:
let filename: string = "document.pdf";
console.log(filename.startsWith("doc")); // true
console.log(filename.endsWith(".pdf")); // true
console.log(filename.endsWith(".docx")); // false
// Validate file types
function isPDFFile(filename: string): boolean {
return filename.toLowerCase().endsWith(".pdf");
}
console.log(isPDFFile("report.PDF")); // true
console.log(isPDFFile("report.doc")); // false
indexOf()β
Find the position of a substring (returns -1 if not found):
let text: string = "Hello World";
console.log(text.indexOf("World")); // 6
console.log(text.indexOf("o")); // 4 (first occurrence)
console.log(text.indexOf("goodbye")); // -1 (not found)
// Check if substring exists
if (text.indexOf("World") !== -1) {
console.log("Found 'World' in the string");
}
// Better way (more modern):
if (text.includes("World")) {
console.log("Found 'World' in the string");
}
lastIndexOf()β
Find the last occurrence:
let text: string = "Hello World, Hello TypeScript";
console.log(text.indexOf("Hello")); // 0 (first occurrence)
console.log(text.lastIndexOf("Hello")); // 13 (last occurrence)
Extracting Substringsβ
slice()β
Extract a portion of a string:
let text: string = "Hello World";
// slice(start, end) - end is not included
console.log(text.slice(0, 5)); // "Hello"
console.log(text.slice(6, 11)); // "World"
console.log(text.slice(6)); // "World" (from index 6 to end)
// Negative indices count from the end
console.log(text.slice(-5)); // "World" (last 5 characters)
console.log(text.slice(-5, -1)); // "Worl"
// Extract file extension
function getFileExtension(filename: string): string {
const dotIndex = filename.lastIndexOf(".");
if (dotIndex === -1) return "";
return filename.slice(dotIndex + 1);
}
console.log(getFileExtension("document.pdf")); // "pdf"
console.log(getFileExtension("archive.tar.gz")); // "gz"
console.log(getFileExtension("README")); // ""
substring()β
Similar to slice, but doesn't support negative indices:
let text: string = "Hello World";
console.log(text.substring(0, 5)); // "Hello"
console.log(text.substring(6)); // "World"
// Negative values treated as 0
console.log(text.substring(-5)); // "Hello World" (not "World")
Recommendation: Use slice() - it's more flexible and intuitive.
Replacing Contentβ
replace()β
Replace the first occurrence:
let text: string = "Hello World";
let newText: string = text.replace("World", "TypeScript");
console.log(newText); // "Hello TypeScript"
// Only replaces first occurrence
let repeated: string = "cat cat cat";
console.log(repeated.replace("cat", "dog")); // "dog cat cat"
replaceAll()β
Replace all occurrences:
let repeated: string = "cat cat cat";
console.log(repeated.replaceAll("cat", "dog")); // "dog dog dog"
// Use with regex for more power
let text: string = "Hello World 123";
console.log(text.replaceAll(/\d/g, "X")); // "Hello World XXX"
Splitting and Joiningβ
split()β
Convert string to array:
let sentence: string = "I love TypeScript";
let words: string[] = sentence.split(" ");
console.log(words); // ["I", "love", "TypeScript"]
// Split into characters
let word: string = "Hello";
let chars: string[] = word.split("");
console.log(chars); // ["H", "e", "l", "l", "o"]
// CSV parsing
let csv: string = "Alice,25,Engineer";
let data: string[] = csv.split(",");
console.log(data); // ["Alice", "25", "Engineer"]
// Limit the number of splits
let text: string = "a-b-c-d-e";
console.log(text.split("-", 3)); // ["a", "b", "c"]
Array join()β
Convert array back to string:
let words: string[] = ["Hello", "World"];
let sentence: string = words.join(" ");
console.log(sentence); // "Hello World"
let path: string[] = ["users", "alice", "documents"];
let fullPath: string = path.join("/");
console.log(fullPath); // "users/alice/documents"
Template Literalsβ
Template literals are the most powerful way to work with strings in TypeScript.
String Interpolationβ
Embed expressions directly in strings:
let name: string = "Alice";
let age: number = 25;
let city: string = "London";
let intro: string = `My name is ${name}. I am ${age} years old and I live in ${city}.`;
console.log(intro);
// "My name is Alice. I am 25 years old and I live in London."
// Expressions work too
let a: number = 5;
let b: number = 3;
console.log(`${a} + ${b} = ${a + b}`); // "5 + 3 = 8"
// Function calls
function getGreeting(): string {
return "Hello";
}
console.log(`${getGreeting()}, World!`); // "Hello, World!"
Multiline Stringsβ
No need for \n:
let poem: string = `
Roses are red,
Violets are blue,
TypeScript is awesome,
And so are you!
`;
console.log(poem);
// HTML templates
let html: string = `
<div class="card">
<h2>Welcome</h2>
<p>This is a template literal</p>
</div>
`;
Tagged Templates (Advanced)β
You can process template literals with functions:
function highlight(strings: TemplateStringsArray, ...values: any[]): string {
return strings.reduce((result, str, i) => {
return result + str + (values[i] ? `<mark>${values[i]}</mark>` : "");
}, "");
}
let name: string = "Alice";
let age: number = 25;
let result: string = highlight`Name: ${name}, Age: ${age}`;
console.log(result);
// "Name: <mark>Alice</mark>, Age: <mark>25</mark>"
TypeScript String Featuresβ
String Literal Typesβ
Restrict a string to specific values:
type Color = "red" | "green" | "blue";
function setColor(color: Color): void {
console.log(`Setting color to ${color}`);
}
setColor("red"); // β
setColor("green"); // β
// setColor("yellow"); // β Error: Argument of type '"yellow"' is not assignable
Template Literal Typesβ
Create types from template strings:
type Greeting = `Hello, ${string}!`;
let greeting1: Greeting = "Hello, World!"; // β
let greeting2: Greeting = "Hello, Alice!"; // β
// let greeting3: Greeting = "Hi, World!"; // β Error
// More complex example
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type Endpoint = "/users" | "/posts" | "/comments";
type APIRoute = `${HTTPMethod} ${Endpoint}`;
let route1: APIRoute = "GET /users"; // β
let route2: APIRoute = "POST /posts"; // β
// let route3: APIRoute = "GET /other"; // β Error
Common String Patternsβ
Validationβ
function isValidEmail(email: string): boolean {
return email.includes("@") && email.includes(".");
}
function isValidURL(url: string): boolean {
return url.startsWith("http://") || url.startsWith("https://");
}
function hasMinimumLength(text: string, minLength: number): boolean {
return text.trim().length >= minLength;
}
Formattingβ
function capitalize(text: string): string {
if (text.length === 0) return text;
return text[0].toUpperCase() + text.slice(1).toLowerCase();
}
console.log(capitalize("hello")); // "Hello"
console.log(capitalize("WORLD")); // "World"
console.log(capitalize("tYpEsCrIpT")); // "Typescript"
function titleCase(text: string): string {
return text
.split(" ")
.map(word => capitalize(word))
.join(" ");
}
console.log(titleCase("hello world")); // "Hello World"
Truncationβ
function truncate(text: string, maxLength: number): string {
if (text.length <= maxLength) return text;
return text.slice(0, maxLength - 3) + "...";
}
console.log(truncate("This is a long string", 10)); // "This is..."
console.log(truncate("Short", 10)); // "Short"
Conceptsβ
Quick Referenceβ
// Creating strings
let single: string = 'Hello';
let double: string = "World";
let template: string = `Hello ${name}`;
// Length
"Hello".length // 5
// Case
"Hello".toUpperCase() // "HELLO"
"Hello".toLowerCase() // "hello"
// Trimming
" Hello ".trim() // "Hello"
" Hello ".trimStart() // "Hello "
" Hello ".trimEnd() // " Hello"
// Searching
"Hello".includes("ell") // true
"Hello".startsWith("Hel") // true
"Hello".endsWith("lo") // true
"Hello".indexOf("l") // 2
// Extracting
"Hello".slice(1, 4) // "ell"
"Hello".substring(1, 4) // "ell"
// Replacing
"Hello".replace("l", "L") // "HeLlo"
"Hello".replaceAll("l", "L") // "HeLLo"
// Splitting
"a,b,c".split(",") // ["a", "b", "c"]
"Hello".split("") // ["H", "e", "l", "l", "o"]
Examplesβ
// Email validator
function validateEmail(email: string): boolean {
email = email.trim().toLowerCase();
return email.includes("@") &&
email.indexOf("@") > 0 &&
email.indexOf("@") < email.length - 1;
}
// URL builder
function buildURL(base: string, path: string, params: Record<string, string>): string {
let url = base + path;
const queryString = Object.entries(params)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join("&");
return queryString ? `${url}?${queryString}` : url;
}
console.log(buildURL("https://api.com", "/users", { id: "123", name: "Alice" }));
// "https://api.com/users?id=123&name=Alice"
// Slugify (convert to URL-friendly format)
function slugify(text: string): string {
return text
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, "")
.replace(/[\s_-]+/g, "-")
.replace(/^-+|-+$/g, "");
}
console.log(slugify("Hello World!")); // "hello-world"
console.log(slugify("TypeScript is Great")); // "typescript-is-great"
Challengesβ
1. Full Name Lengthβ
- Create a string variable with your full name.
- Print the length of the string.
- Create a function that returns the length of any string.
π‘ Show Answer
let fullName: string = "Alice Johnson";
console.log(fullName.length); // 13
// Function version
function getStringLength(text: string): number {
return text.length;
}
console.log(getStringLength("Hello World")); // 11
console.log(getStringLength("")); // 0
// With validation
function getValidLength(text: string | null | undefined): number {
if (!text) return 0;
return text.length;
}
console.log(getValidLength("Hello")); // 5
console.log(getValidLength(null)); // 0
console.log(getValidLength(undefined)); // 0
// Count without spaces
function getLengthWithoutSpaces(text: string): number {
return text.replace(/\s/g, "").length;
}
console.log(getLengthWithoutSpaces("Hello World")); // 10
2. Case Conversionβ
- Convert the string "TypeScript" to uppercase.
- Convert it to lowercase.
- Create a function that toggles between upper and lower case.
π‘ Show Answer
let language: string = "TypeScript";
console.log(language.toUpperCase()); // "TYPESCRIPT"
console.log(language.toLowerCase()); // "typescript"
// Toggle case function
function toggleCase(text: string): string {
return text
.split("")
.map(char =>
char === char.toUpperCase()
? char.toLowerCase()
: char.toUpperCase()
)
.join("");
}
console.log(toggleCase("Hello World")); // "hELLO wORLD"
console.log(toggleCase("TypeScript")); // "tYPEsCRIPT"
// Title case
function toTitleCase(text: string): string {
return text
.toLowerCase()
.split(" ")
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
}
console.log(toTitleCase("hello world")); // "Hello World"
console.log(toTitleCase("typescript is great")); // "Typescript Is Great"
3. Trim Whitespaceβ
- Take the string " Hello World " and remove whitespace from both ends.
- Create functions to trim only the start or only the end.
- Demonstrate the difference between each method.
π‘ Show Answer
let messy: string = " Hello World ";
console.log(messy.trim()); // "Hello World"
console.log(messy.trimStart()); // "Hello World "
console.log(messy.trimEnd()); // " Hello World"
// Show the difference with length
console.log("Original length:", messy.length); // 17
console.log("After trim:", messy.trim().length); // 11
console.log("After trimStart:", messy.trimStart().length); // 14
console.log("After trimEnd:", messy.trimEnd().length); // 14
// Clean user input function
function cleanInput(input: string): string {
return input.trim();
}
console.log(cleanInput(" alice@email.com ")); // "alice@email.com"
// Remove all whitespace
function removeAllWhitespace(text: string): string {
return text.replace(/\s/g, "");
}
console.log(removeAllWhitespace(" Hello World ")); // "HelloWorld"
// Normalize whitespace (multiple spaces to single)
function normalizeWhitespace(text: string): string {
return text.trim().replace(/\s+/g, " ");
}
console.log(normalizeWhitespace("Hello World Today")); // "Hello World Today"
4. Substring Searchβ
- Check if "banana" contains "na".
- Find the first position of "na" in "banana".
- Count how many times "na" appears in "banana".
π‘ Show Answer
let fruit: string = "banana";
// Check if contains
console.log(fruit.includes("na")); // true
// Find first position
console.log(fruit.indexOf("na")); // 2
// Count occurrences
function countOccurrences(text: string, search: string): number {
let count = 0;
let position = 0;
while ((position = text.indexOf(search, position)) !== -1) {
count++;
position += search.length;
}
return count;
}
console.log(countOccurrences("banana", "na")); // 2
console.log(countOccurrences("mississippi", "ss")); // 2
console.log(countOccurrences("hello", "l")); // 2
// Alternative with split
function countOccurrencesAlt(text: string, search: string): number {
return text.split(search).length - 1;
}
console.log(countOccurrencesAlt("banana", "na")); // 2
// Case-insensitive search
function includesIgnoreCase(text: string, search: string): boolean {
return text.toLowerCase().includes(search.toLowerCase());
}
console.log(includesIgnoreCase("Hello World", "WORLD")); // true
5. Extract Substringβ
- Extract "Script" from "JavaScript" using slice.
- Get the first 4 characters of "JavaScript".
- Get the last 6 characters of "JavaScript".
π‘ Show Answer
let language: string = "JavaScript";
// Extract "Script"
console.log(language.slice(4)); // "Script"
console.log(language.slice(4, 10)); // "Script"
// First 4 characters
console.log(language.slice(0, 4)); // "Java"
// Last 6 characters
console.log(language.slice(-6)); // "Script"
console.log(language.slice(language.length - 6)); // "Script"
// Extract middle portion
console.log(language.slice(2, 8)); // "vaScri"
// Get file extension
function getExtension(filename: string): string {
const dotIndex = filename.lastIndexOf(".");
if (dotIndex === -1) return "";
return filename.slice(dotIndex + 1);
}
console.log(getExtension("document.pdf")); // "pdf"
console.log(getExtension("photo.jpg")); // "jpg"
console.log(getExtension("archive.tar.gz")); // "gz"
console.log(getExtension("README")); // ""
// Get filename without extension
function removeExtension(filename: string): string {
const dotIndex = filename.lastIndexOf(".");
if (dotIndex === -1) return filename;
return filename.slice(0, dotIndex);
}
console.log(removeExtension("document.pdf")); // "document"
console.log(removeExtension("README")); // "README"
6. Split Into Wordsβ
- Split "I love coding" into an array of words.
- Join the words back with a different separator.
- Reverse the order of words.
π‘ Show Answer
let sentence: string = "I love coding";
// Split into words
let words: string[] = sentence.split(" ");
console.log(words); // ["I", "love", "coding"]
// Join with different separator
console.log(words.join("-")); // "I-love-coding"
console.log(words.join(", ")); // "I, love, coding"
console.log(words.join("")); // "Ilovecoding"
// Reverse word order
let reversed: string = words.reverse().join(" ");
console.log(reversed); // "coding love I"
// Split into characters
let word: string = "Hello";
let chars: string[] = word.split("");
console.log(chars); // ["H", "e", "l", "l", "o"]
// CSV parsing
function parseCSV(csv: string): string[][] {
return csv.split("\n").map(line => line.split(","));
}
let data = `Name,Age,City
Alice,25,London
Bob,30,Paris`;
console.log(parseCSV(data));
// [["Name","Age","City"], ["Alice","25","London"], ["Bob","30","Paris"]]
// Word count
function countWords(text: string): number {
return text.trim().split(/\s+/).length;
}
console.log(countWords("Hello World")); // 2
console.log(countWords("I love TypeScript")); // 3
7. Replace Textβ
- Replace "bad" with "good" in "This is bad".
- Replace all occurrences of "cat" with "dog" in "cat cat cat".
- Create a function to censor words in a string.
π‘ Show Answer
// Replace first occurrence
let text1: string = "This is bad";
console.log(text1.replace("bad", "good")); // "This is good"
// Replace all occurrences
let text2: string = "cat cat cat";
console.log(text2.replaceAll("cat", "dog")); // "dog dog dog"
// Censor function
function censorWord(text: string, word: string): string {
const replacement = "*".repeat(word.length);
return text.replaceAll(word, replacement);
}
console.log(censorWord("This is bad", "bad")); // "This is ***"
console.log(censorWord("dog cat dog", "dog")); // "*** cat ***"
// Censor multiple words
function censorWords(text: string, words: string[]): string {
let result = text;
for (const word of words) {
result = censorWord(result, word);
}
return result;
}
console.log(censorWords("bad dog and cat", ["bad", "dog"])); // "*** *** and cat"
// Remove all numbers
function removeNumbers(text: string): string {
return text.replace(/\d/g, "");
}
console.log(removeNumbers("Hello 123 World 456")); // "Hello World "
// Replace with function
function replaceWithLength(text: string): string {
return text.replace(/\w+/g, (match) => match.length.toString());
}
console.log(replaceWithLength("Hello World")); // "5 5"
8. Template Literal Practiceβ
- Create a multiline string with your name and a message.
- Use template literals to build a sentence with multiple variables.
- Create an HTML string using template literals.
π‘ Show Answer
// Multiline string
let name: string = "Alice Johnson";
let message: string = `
Hello, my name is ${name}.
I am learning TypeScript.
This is a multiline string!
`;
console.log(message);
// Multiple variables
let firstName: string = "Alice";
let lastName: string = "Johnson";
let age: number = 25;
let city: string = "London";
let bio: string = `${firstName} ${lastName} is ${age} years old and lives in ${city}.`;
console.log(bio);
// HTML template
function createCard(title: string, content: string): string {
return `
<div class="card">
<h2>${title}</h2>
<p>${content}</p>
<button>Read More</button>
</div>
`;
}
console.log(createCard("Welcome", "This is a TypeScript tutorial"));
// Table generator
function createTable(headers: string[], rows: string[][]): string {
return `
<table>
<thead>
<tr>${headers.map(h => `<th>${h}</th>`).join("")}</tr>
</thead>
<tbody>
${rows.map(row =>
`<tr>${row.map(cell => `<td>${cell}</td>`).join("")}</tr>`
).join("")}
</tbody>
</table>
`;
}
let table = createTable(
["Name", "Age"],
[["Alice", "25"], ["Bob", "30"]]
);
console.log(table);
// Expression evaluation
let x: number = 10;
let y: number = 5;
console.log(`${x} + ${y} = ${x + y}`); // "10 + 5 = 15"
console.log(`${x} * ${y} = ${x * y}`); // "10 * 5 = 50"
9. Vowel Counterβ
- Write a function that counts vowels in a string.
- Make it case-insensitive.
- Return both vowel count and consonant count.
π‘ Show Answer
function countVowels(text: string): number {
const vowels = "aeiouAEIOU";
let count = 0;
for (const char of text) {
if (vowels.includes(char)) {
count++;
}
}
return count;
}
console.log(countVowels("Hello World")); // 3
console.log(countVowels("TypeScript")); // 2
console.log(countVowels("AEIOU")); // 5
// With reduce
function countVowelsReduce(text: string): number {
const vowels = "aeiouAEIOU";
return text.split("").reduce((count, char) =>
vowels.includes(char) ? count + 1 : count, 0
);
}
// Count vowels and consonants
function countLetters(text: string): { vowels: number; consonants: number } {
const vowels = "aeiouAEIOU";
const letters = text.replace(/[^a-zA-Z]/g, "");
const vowelCount = letters.split("").filter(char => vowels.includes(char)).length;
const consonantCount = letters.length - vowelCount;
return { vowels: vowelCount, consonants: consonantCount };
}
console.log(countLetters("Hello World!"));
// { vowels: 3, consonants: 7 }
// Get individual vowel counts
function getVowelBreakdown(text: string): Record<string, number> {
const vowels = "aeiou";
const result: Record<string, number> = { a: 0, e: 0, i: 0, o: 0, u: 0 };
for (const char of text.toLowerCase()) {
if (vowels.includes(char)) {
result[char]++;
}
}
return result;
}
console.log(getVowelBreakdown("Hello World"));
// { a: 0, e: 1, i: 0, o: 2, u: 0 }
10. Palindrome Checkerβ
- Create a function that checks if a string is a palindrome.
- Make it case-insensitive and ignore spaces/punctuation.
- Test with various strings including phrases.
π‘ Show Answer
function isPalindrome(text: string): boolean {
// Clean the string: lowercase and remove non-alphanumeric
const cleaned = text.toLowerCase().replace(/[^a-z0-9]/g, "");
// Compare with reversed version
const reversed = cleaned.split("").reverse().join("");
return cleaned === reversed;
}
console.log(isPalindrome("racecar")); // true
console.log(isPalindrome("hello")); // false
console.log(isPalindrome("A man a plan a canal Panama")); // true
console.log(isPalindrome("race car")); // true
console.log(isPalindrome("Was it a car or a cat I saw?")); // true
// Alternative implementation
function isPalindromeAlt(text: string): boolean {
const cleaned = text.toLowerCase().replace(/[^a-z0-9]/g, "");
const len = cleaned.length;
for (let i = 0; i < len / 2; i++) {
if (cleaned[i] !== cleaned[len - 1 - i]) {
return false;
}
}
return true;
}
// Find longest palindrome substring
function longestPalindrome(text: string): string {
let longest = "";
for (let i = 0; i < text.length; i++) {
for (let j = i + 1; j <= text.length; j++) {
const substring = text.slice(i, j);
if (isPalindrome(substring) && substring.length > longest.length) {
longest = substring;
}
}
}
return longest;
}
console.log(longestPalindrome("babad")); // "bab" or "aba"
console.log(longestPalindrome("racecar is a racecar")); // "racecar"
// Count palindromes in a sentence
function countPalindromeWords(sentence: string): number {
const words = sentence.toLowerCase().split(/\s+/);
return words.filter(word => isPalindrome(word)).length;
}
console.log(countPalindromeWords("mom and dad saw a racecar")); // 4
Summaryβ
In this chapter, you learned:
β How to create strings with single quotes, double quotes, and template literals
β
String properties like length
β
Case conversion with toUpperCase() and toLowerCase()
β
Trimming whitespace with trim(), trimStart(), and trimEnd()
β
Searching strings with includes(), indexOf(), startsWith(), and endsWith()
β
Extracting substrings with slice() and substring()
β
Replacing content with replace() and replaceAll()
β Splitting strings into arrays and joining them back
β Template literals for interpolation and multiline strings
β TypeScript string literal types and template literal types
Key Takeaways:
- Strings are immutable - methods return new strings
- Template literals are the most powerful and modern way to work with strings
- TypeScript's type system prevents common string-related bugs
- String methods are chainable for powerful transformations
- Always validate and sanitize user input strings
- Use type-safe string literal types when you need specific string values
Best Practices:
- Use template literals for string interpolation
- Always trim user input
- Use case-insensitive comparisons for user-facing text
- Validate string format before processing (emails, URLs, etc.)
- Use descriptive variable names for strings
- Consider using string literal types for constants
In the next chapter, we'll explore Objects and learn how to structure data with TypeScript's powerful type system!
Continue to Chapter 6: Objects β