Napisy i szablony tekstowe

Tekst to najczęściej przetwarzany rodzaj danych w aplikacjach webowych. Poznajesz kilkanaście metod, które robią z nim wszystko: przycinają, szukają, podmieniają i formatują — a na koniec budujesz generator szkolnych adresów e-mail.

TypeScript string metody tekstu szablony 50 min
CEL LEKCJI

Czego się dziś nauczysz

  • Zbudujesz komunikat szablonem w backtickach zamiast sklejania plusami
  • Wybierzesz właściwą metodę do wyszukiwania, wycinania i podmiany fragmentu tekstu
  • Sformatujesz tabelkę w konsoli, wyrównując kolumny
  • Wyjaśnisz, dlaczego tekst.toUpperCase() nie zmienia zmiennej tekst
  • Napiszesz program zamieniający dane osobowe na login i adres e-mail
TEORIA

Szablony tekstowe

Sklejanie plusami działa, ale przy dłuższych komunikatach robi się nieczytelne — łatwo zgubić spację albo cudzysłów. Szablon w backtickach rozwiązuje oba problemy:

src/index.ts
const imie = "Marta";
const klasa = "3TI";
const punkty = 37;
const maks = 40;

// sklejanie plusami — czytelne tylko przy dwóch elementach
console.log("Uczennica " + imie + " z klasy " + klasa + " ma " + punkty + "/" + maks + " pkt");

// szablon — to samo, ale widać strukturę zdania
console.log(`Uczennica ${imie} z klasy ${klasa} ma ${punkty}/${maks} pkt`);

W nawiasach ${…} może stanąć dowolne wyrażenie — nie tylko nazwa zmiennej:

src/index.ts
const punkty = 37;
const maks = 40;
console.log(`Wynik: ${((punkty / maks) * 100).toFixed(1)}%`);
console.log(`Status: ${punkty >= 20 ? "zdany" : "niezdany"}`);
console.log(`Do maksimum brakuje ${maks - punkty} pkt`);

Tekst wielolinijkowy

Szablon zachowuje wszystkie złamania wierszy zapisane w kodzie — nie trzeba już \n ani sklejania:

src/index.ts
const uczen = "Marta Kowalska";
const srednia = 4.36;

const swiadectwo = `
╔════════════════════════════════════╗
║  ŚWIADECTWO ŚRÓDROCZNE
║  Uczeń:   ${uczen}
║  Średnia: ${srednia.toFixed(2)}
║  Wynik:   ${srednia >= 4.75 ? "z wyróżnieniem" : "promocja"}
╚════════════════════════════════════╝
`;

console.log(swiadectwo);

Backtick na klawiaturze

Znak ` znajdziesz na klawiszu obok lewego Shifta (na układzie polskim programisty) lub pod Escape. To nie jest apostrof ' — apostrof nie uruchomi podstawiania ${…}.

TEORIA

Znaki specjalne

ZapisZnaczeniePrzykład
\nnowa linia"Linia 1\nLinia 2"
\ttabulator"Imię\tOcena"
\"cudzysłów wewnątrz tekstu"Powiedział \"cześć\""
\\ukośnik wsteczny"C:\\Users\\uczen"
\`backtick w szablonie`znak \` w tekście`
src/index.ts
console.log("Imię\tOcena\n----\t-----\nAla\t5\nBartek\t4");
console.log("Ścieżka: C:\\Program Files\\Node");
console.log('Uczeń powiedział: "to działa!"');   // apostrofy pozwalają uniknąć ukośników
wynik w konsoli
Imię	Ocena
----	-----
Ala	5
Bartek	4
Ścieżka: C:\Program Files\Node
Uczeń powiedział: "to działa!"
PRZEGLĄD

Metody tekstu, których naprawdę używasz

Podstawowe informacje

src/index.ts
const tekst = "  Programowanie w TypeScript  ";

console.log(tekst.length);            // 30 — razem ze spacjami
console.log(tekst.trim());            // "Programowanie w TypeScript"
console.log(tekst.trim().length);     // 26
console.log(tekst.toUpperCase());     // WIELKIMI LITERAMI
console.log(tekst.toLowerCase());     // małymi literami

Szukanie

src/index.ts
const mail = "marta.kowalska@zsmi.edu.pl";

console.log(mail.includes("@"));           // true  — czy zawiera
console.log(mail.startsWith("marta"));     // true  — czy zaczyna się od
console.log(mail.endsWith(".pl"));         // true  — czy kończy się na
console.log(mail.indexOf("@"));            // 14    — na której pozycji
console.log(mail.indexOf("xyz"));          // -1    — nie znaleziono

Numerowanie zaczyna się od zera

Pierwszy znak tekstu ma numer 0, ostatni ma numer length - 1. Metoda indexOf zwraca -1, gdy niczego nie znajdzie — dlatego typowy warunek to if (mail.indexOf("@") !== -1), choć czytelniejsze jest po prostu if (mail.includes("@")).

Wycinanie fragmentów

src/index.ts
const pesel = "04231512345";

console.log(pesel.slice(0, 2));      // "04"  — rok
console.log(pesel.slice(2, 4));      // "23"  — miesiąc (z zakodowanym stuleciem)
console.log(pesel.slice(4, 6));      // "15"  — dzień
console.log(pesel.slice(-1));        // "5"   — ostatni znak
console.log(pesel.charAt(0));        // "0"   — pojedynczy znak
console.log(pesel[0]);               // "0"   — to samo, krócej

W slice(od, do) pierwszy numer jest brany, a drugi już nie — wycinamy „do, ale bez”. Dzięki temu slice(0, 2) daje dokładnie dwa znaki.

Zmiana treści

src/index.ts
const zdanie = "kot ma ala, ala ma kota";

console.log(zdanie.replace("ala", "Ola"));      // tylko pierwsze wystąpienie
console.log(zdanie.replaceAll("ala", "Ola"));   // wszystkie wystąpienia
console.log("ab".repeat(3));                    // "ababab"
console.log("7".padStart(3, "0"));              // "007" — wiodące zera
console.log("Ala".padEnd(10, ".") + "|");       // "Ala.......|" — wyrównanie kolumn

Ściąga

MetodaDo czego
.lengthliczba jednostek UTF-16; dla zwykłych liter często odpowiada liczbie znaków. Właściwość, bez nawiasów.
.trim()Usuwa białe znaki z początku i końca. Używaj, gdy otaczające spacje nie są częścią danych; nie przycinaj automatycznie np. haseł.
.toUpperCase() / .toLowerCase()zmiana wielkości liter, także przed porównaniem
.includes(x)czy tekst zawiera fragment
.startsWith(x) / .endsWith(x)sprawdzenie początku lub końca
.indexOf(x)pozycja fragmentu albo -1
.slice(od, do)wycięcie fragmentu; liczby ujemne liczą od końca
.replace(a, b) / .replaceAll(a, b)podmiana pierwszego / wszystkich wystąpień
.split(x)rozbicie tekstu na tablicę (lekcja 08)
.padStart(n, z) / .padEnd(n, z)dopełnienie do zadanej długości
.repeat(n)powtórzenie tekstu — świetne do rysowania linii
MECHANIZM

Tekstu nie da się zmienić

To najczęstsze potknięcie na tym etapie. Żadna metoda tekstu nie modyfikuje oryginału — każda zwraca nowy tekst:

src/index.ts
let nazwa = "  ala  ";

nazwa.trim();                 // wynik wyrzucony do kosza!
console.log(`[${nazwa}]`);    // [  ala  ] — bez zmian

nazwa = nazwa.trim();         // tak jest dobrze
console.log(`[${nazwa}]`);    // [ala]

// metody można łączyć w łańcuch — każda działa na wyniku poprzedniej
const login = "  Marta Kowalska ".trim().toLowerCase().replace(" ", ".");
console.log(login);           // marta.kowalska

Nie da się też podmienić pojedynczego znaku

nazwa[0] = "A"; nie zgłosi błędu w JavaScripcie, ale też nic nie zrobi. Żeby zmienić pierwszą literę, buduje się nowy tekst: nazwa = nazwa[0].toUpperCase() + nazwa.slice(1);

PRZYKŁAD Z OMÓWIENIEM

Generator kont szkolnych

Administrator dostaje listę uczniów i musi utworzyć im konta. Program zamienia dane osobowe na login, adres e-mail i hasło startowe według ustalonych reguł.

src/index.ts
// ── dane wejściowe, tak jak przychodzą z arkusza ──
const imieSurowe = "  Łukasz ";
const nazwiskoSurowe = "Wiśniewski-Nowak ";
const klasa = "3ti";
const numerWDzienniku = 7;

const DOMENA = "zsmi.edu.pl";

// ── 1. Porządkowanie danych ──
const imie = imieSurowe.trim();
const nazwisko = nazwiskoSurowe.trim();

// ── 2. Usunięcie polskich znaków ──
const bezOgonkow = (nazwisko + "." + imie)
  .toLowerCase()
  .replaceAll("ą", "a").replaceAll("ć", "c").replaceAll("ę", "e")
  .replaceAll("ł", "l").replaceAll("ń", "n").replaceAll("ó", "o")
  .replaceAll("ś", "s").replaceAll("ź", "z").replaceAll("ż", "z");

// ── 3. Usunięcie znaków niedozwolonych w loginie ──
const login = bezOgonkow.replaceAll("-", "").replaceAll(" ", "");

// ── 4. Adres e-mail i hasło startowe ──
const email = `${login}@${DOMENA}`;
const numerZZerem = String(numerWDzienniku).padStart(2, "0");
const haslo = `${klasa.toUpperCase()}-${imie.slice(0, 1).toUpperCase()}${nazwisko.slice(0, 3).toLowerCase()}-${numerZZerem}`;

// ── 5. Raport ──
console.log("─".repeat(46));
console.log("Uczeń:".padEnd(10) + `${imie} ${nazwisko}`);
console.log("Klasa:".padEnd(10) + klasa.toUpperCase());
console.log("Login:".padEnd(10) + login);
console.log("E-mail:".padEnd(10) + email);
console.log("Hasło:".padEnd(10) + haslo);
console.log("─".repeat(46));
console.log(`Długość loginu: ${login.length} znaków`);
wynik w konsoli
──────────────────────────────────────────────
Uczeń:    Łukasz Wiśniewski-Nowak
Klasa:    3TI
Login:    wisniewskinowak.lukasz
E-mail:   wisniewskinowak.lukasz@zsmi.edu.pl
Hasło:    3TI-Łwiś-07
──────────────────────────────────────────────
Długość loginu: 22 znaków

Omówienie krok po kroku

FragmentPo co
.trim() na wejściu Dane kopiowane z arkuszy niemal zawsze mają zbędne spacje. Bez tego login zacząłby się od spacji i konto byłoby nie do użycia.
łańcuch .replaceAll(…) Adresy e-mail nie powinny zawierać polskich znaków. Każde wywołanie działa na wyniku poprzedniego — to bezpośrednia konsekwencja niezmienności tekstu.
String(numer).padStart(2, "0") Numer 7 staje się "07". Najpierw zamiana liczby na tekst, bo padStart jest metodą tekstu, nie liczby.
nazwisko.slice(0, 3) Trzy pierwsze litery nazwiska do hasła startowego. Zwróć uwagę: znaki polskie tu zostają, bo hasło nie musi ich unikać.
"Uczeń:".padEnd(10) Wyrównanie kolumn w konsoli. Prostszy i pewniejszy sposób niż liczenie tabulatorów.
"─".repeat(46) Linia oddzielająca. Zamiast wklejać 46 znaków, mówimy programowi, żeby je powtórzył.

Jak zrobiłby to zawodowiec

Dziewięć wywołań replaceAll to sporo powtórzeń. W prawdziwym projekcie użyłoby się jednego wyrażenia regularnego albo metody normalize("NFD"). Tutaj wersja „ręczna” jest czytelniejsza — a do funkcji, które pozwolą to porządnie opakować, dojdziemy w lekcji 11.

CZĘSTE BŁĘDY

Na co uważać

KodProblem
tekst.length()length to właściwość, nie metoda — bez nawiasów.
tekst.trim(); bez przypisaniaWynik przepada. Musi być tekst = tekst.trim();
'Cześć ${imie}'Podstawianie działa tylko w backtickach, nie w apostrofach.
tekst.slice(1, 3) gdy chcesz 3 znakiDostaniesz dwa. Drugi numer to pozycja, przed którą kończymy.
"Ala" === "ala"Fałsz. Przed porównaniem sprowadź obie strony do jednej wielkości liter.
"5" + 3Sklejanie, nie dodawanie. Najpierw Number("5").

Warunki w przykładach

Fragmenty z if służą tu wyłącznie pokazaniu, jak używa się wyniku indexOf albo includes. Samą instrukcję warunkową omawiamy w lekcji 06 — żadne zadanie z tej lekcji nie wymaga jej napisania.

ZADANIA

Zadania

ZAD 1Przewidź wynik★☆☆
zagadka.ts
const s = "TypeScript";
console.log(s.length);
console.log(s.slice(0, 4));
console.log(s.slice(-6));
console.log(s.toUpperCase().includes("SCRIPT"));
console.log(s.indexOf("z"));
console.log("=".repeat(5));
pokaż rozwiązanie
10
Type
Script
true
-1        małe "z" nie występuje — jest wielkie "S"... i małe "cript"
=====
ZAD 2Wizytówka szablonem★☆☆

Przepisz swoją wizytówkę z lekcji 2, zastępując wszystkie sklejania plusami jednym szablonem wielolinijkowym w backtickach. Dodaj linię obliczeniową, na przykład liczbę lat do matury.

ZAD 3Walidacja adresu e-mail★★☆

Sprawdź uproszczone reguły poprawności adresu zapisanego w zmiennej: zawiera dokładnie jeden znak @, ma co najmniej 5 znaków, nie zaczyna się i nie kończy kropką, a po znaku @ występuje kropka. Wypisz wynik każdego sprawdzenia osobno oraz ocenę końcową.

pokaż wskazówki i rozwiązanie
const email = "marta.kowalska@zsmi.edu.pl";

const poz = email.indexOf("@");
const jedenMalpa = poz !== -1 && email.indexOf("@", poz + 1) === -1;
const dlugoscOk = email.length >= 5;
const kropkiOk = !email.startsWith(".") && !email.endsWith(".");
const domenaOk = poz !== -1 && email.slice(poz).includes(".");

console.log(`jeden @:      ${jedenMalpa}`);
console.log(`długość:      ${dlugoscOk}`);
console.log(`kropki:       ${kropkiOk}`);
console.log(`domena:       ${domenaOk}`);
console.log(`ADRES ${jedenMalpa && dlugoscOk && kropkiOk && domenaOk ? "POPRAWNY" : "BŁĘDNY"}`);

indexOf przyjmuje drugi argument — pozycję, od której zacząć szukanie. Dzięki temu sprawdzamy, czy za pierwszą małpą jest jeszcze jedna.

ZAD 4Maskowanie danych★★☆

Napisz program, który ukrywa część danych, tak jak robią to systemy bankowe:

  • numer telefonu "501234567""501***567"
  • adres "marta.kowalska@zsmi.edu.pl""ma***********@zsmi.edu.pl"
  • numer karty "4532015112830366""**** **** **** 0366"

Nie wpisuj gwiazdek ręcznie — policz, ile ich potrzeba, i użyj repeat.

pokaż rozwiązanie
const tel = "501234567";
const maskaTel = tel.slice(0, 3) + "*".repeat(tel.length - 6) + tel.slice(-3);
console.log(maskaTel);

const mail = "marta.kowalska@zsmi.edu.pl";
const poz = mail.indexOf("@");
const maskaMail = mail.slice(0, 2) + "*".repeat(poz - 2) + mail.slice(poz);
console.log(maskaMail);

const karta = "4532015112830366";
console.log(`**** **** **** ${karta.slice(-4)}`);
ZAD 5Analiza PESEL★★★

Mając numer PESEL w zmiennej tekstowej, wyłuskaj i wypisz: rok, miesiąc i dzień urodzenia oraz płeć (przedostatnia cyfra: parzysta oznacza kobietę, nieparzysta mężczyznę). Sprawdź też, czy numer ma dokładnie 11 znaków. Załóż na razie, że osoba urodziła się w latach 1900–1999 (miesiąc bez dodatku stulecia).

pokaż rozwiązanie
const pesel = "94051812345";

const dlugoscOk = pesel.length === 11;

const rok = 1900 + Number(pesel.slice(0, 2));
const miesiac = pesel.slice(2, 4);
const dzien = pesel.slice(4, 6);
const cyfraPlci = Number(pesel[9]);
const plec = cyfraPlci % 2 === 0 ? "kobieta" : "mężczyzna";

console.log(`Poprawna długość: ${dlugoscOk}`);
console.log(`Data urodzenia:   ${dzien}.${miesiac}.${rok}`);
console.log(`Płeć:             ${plec}`);

Zwróć uwagę, że dzień i miesiąc zostawiamy jako tekst — chcemy zachować wiodące zera ("05", a nie 5). Rok musi być liczbą, bo dodajemy do niego 1900. Wybór między tekstem a liczbą zależy od tego, co zamierzasz z daną zrobić.

Granice przykładów

"😀".length daje 2, bo length liczy jednostki UTF-16. charAt poza zakresem daje pusty tekst, a indeksowanie tekst[i] daje undefined. Reguły hasła, adresu e-mail i wycinanie PESEL w zadaniach są uproszczeniami do nauki metod tekstu: generator nie tworzy bezpiecznego hasła, a wycinanie daty nie sprawdza całego numeru ani sumy kontrolnej.

PODSUMOWANIE

Co trzeba zapamiętać

  • Szablon w backtickach z ${…} zastępuje sklejanie plusami i obsługuje wiele linii.
  • Żadna metoda nie zmienia oryginalnego tekstu — zawsze przypisuj wynik.
  • Metody można łączyć w łańcuch: tekst.trim().toLowerCase().replace(…)
  • Znaki numeruje się od zera; slice(od, do) nie bierze znaku spod numeru do.
  • Przycinaj otaczające białe znaki tylko tam, gdzie zgadza się to z regułą danych.
  • padStart, padEnd i repeat robią porządek w wypisywanych raportach.