Pytania rekrutacyjne Typescript
50 pytań — 20 odpowiedzi dostępnych od razu
Podstawy TypeScript
Czym jest TypeScript i jakie korzyści płyną z jego używania w porównaniu do standardowego JavaScript?
TypeScript to język programowania, który stanowi nadzbiór JavaScript. Oznacza to, że każdy poprawny kod JavaScript jest również poprawnym kodem TypeScript, przy czym TypeScript wprowadza dodatkowe funkcjonalności, takie jak statyczne typowanie oraz zaawansowaną obsługę obiektowości. Główne korzyści z używania TypeScript to:
- Statyczne typowanie: Pozwala na wychwycenie wielu błędów już na etapie kompilacji, co zwiększa stabilność i bezpieczeństwo kodu.
- Lepsza czytelność kodu: Wprowadzenie typów i interfejsów ułatwia zrozumienie struktury projektu, szczególnie w dużych aplikacjach.
- Wsparcie nowoczesnych funkcji: Umożliwia korzystanie z najnowszych funkcji ECMAScript, które są następnie kompilowane do JavaScript kompatybilnego z wybranymi środowiskami.
- Rozbudowane narzędzia: Dzięki integracji z edytorami i IDE, takimi jak Visual Studio Code czy IntelliJ IDEA, możliwe jest korzystanie z inteligentnego podpowiadania kodu oraz refaktoryzacji.
Dalsze informacje na temat TypeScript można znaleźć w oficjalnej dokumentacji TypeScript oraz na artykułach na Wikipedii (polska wersja).
Jak zainstalować i skonfigurować kompilator TypeScript w projekcie?
Aby rozpocząć pracę z TypeScript, należy zainstalować kompilator. Najprostszym sposobem jest użycie npm (Node Package Manager). Przykładowo:
Instalacja globalna (umożliwia korzystanie z polecenia
tscw dowolnym miejscu):npm install -g typescriptInstalacja lokalna (zalecana w projektach, aby wersja kompilatora była zależna od projektu):
npm install --save-dev typescriptInicjalizacja konfiguracji: Po instalacji warto wygenerować plik
tsconfig.json, który jest głównym narzędziem konfiguracyjnym TypeScript:npx tsc --initPlik
tsconfig.jsonpozwala m.in. określić docelową wersję ECMAScript, dołączane pliki, zakres błędów oraz dodatkowe opcje kompilatora.
Więcej informacji na temat konfiguracji znajdziesz w dokumentacji TypeScript dotyczącej konfiguracji.
W jaki sposób działa proces kompilacji TypeScript do JavaScript?
Proces kompilacji w TypeScript przebiega następująco:
- Analiza kodu: Kompilator analizuje kod źródłowy, sprawdzając zgodność typów i składnię.
- Transpilacja: Kod napisany w TypeScript jest transpilowany do czystego JavaScript, zgodnie z ustawieniami określonymi w
tsconfig.json(np. docelowa wersja ECMAScript, moduły itp.). - Generowanie map źródeł (opcjonalnie): W przypadku włączenia opcji generacji map źródeł (
sourceMap), kompilator tworzy pliki.map, które umożliwiają debugowanie kodu oryginalnego TS w narzędziach developerskich. - Optymalizacja i wyświetlanie błędów: W trakcie kompilacji sprawdzane są potencjalne błędy, a także możliwe są pewne optymalizacje w generowanym kodzie JavaScript (w zależności od ustawień).
Szczegółowy opis procesu znajdziesz w sekcji dotyczącej kompilacji w dokumentacji TypeScript.
Jakie są główne różnice między TypeScript a JavaScript?
Podstawowe różnice pomiędzy TypeScript a JavaScript obejmują:
Typowanie:
- TypeScript: Wprowadza statyczne typowanie, co umożliwia deklarację typów dla zmiennych, funkcji i obiektów.
- JavaScript: Jest językiem dynamicznie typowanym, gdzie typy są określane w czasie wykonywania.
Narzędzia i wsparcie IDE:
- TypeScript: Dzięki statycznej analizie kodu, edytory zapewniają zaawansowane funkcje takie jak podpowiedzi, automatyczne uzupełnianie, refaktoryzację oraz wykrywanie błędów już podczas pisania kodu.
- JavaScript: Choć również posiada wsparcie w nowoczesnych edytorach, brak statycznych typów ogranicza możliwości w tym zakresie.
Nowoczesne funkcjonalności:
- TypeScript: Pozwala na korzystanie z najnowszych funkcji ECMAScript oraz dodatkowych mechanizmów obiektowych (np. interfejsów, typów generycznych), które są następnie transpilowane do kompatybilnej wersji JavaScript.
- JavaScript: Bezpośrednio używa jedynie funkcjonalności dostępnych w specyfikacji języka, co może wiązać się z koniecznością stosowania dodatkowych polyfilli lub bibliotek w starszych środowiskach.
Dla dogłębnej analizy różnic warto zapoznać się z artykułami porównawczymi, np. porównanie TypeScript i JavaScript na blogu lub w polskiej wersji Wikipedii.
Typy danych i zmienne
Jakie są podstawowe typy danych dostępne w TypeScript?
W TypeScript dostępne są następujące typy danych:
- number – reprezentuje liczby, zarówno całkowite, jak i zmiennoprzecinkowe.
- string – reprezentuje ciągi znaków.
- boolean – reprezentuje wartość logiczną
truelubfalse. - null i undefined – reprezentują odpowiednio brak wartości i niezdefiniowaną wartość.
- symbol – unikalny identyfikator, używany przy tworzeniu unikalnych właściwości obiektów.
- bigint – służy do reprezentacji bardzo dużych liczb całkowitych.
- any – wyłącza statyczne sprawdzanie typów, pozwalając na dowolną wartość.
- unknown – bezpieczniejsza alternatywa dla
any, wymaga dodatkowego sprawdzenia typu przed użyciem. - void – najczęściej używany jako typ zwracany przez funkcje, które nie zwracają żadnej wartości.
- never – reprezentuje typ funkcji, które nigdy nie kończą działania (np. funkcje rzucające wyjątek).
Więcej informacji na temat podstawowych typów dostępnych w TypeScript znajdziesz w oficjalnej dokumentacji TypeScript – Basic Types.
Jak deklarować zmienne w TypeScript i czym różnią się let, const oraz var?
W TypeScript (oraz w JavaScript) zmienne można deklarować przy użyciu trzech słów kluczowych:
- let
Używane do deklarowania zmiennych o zasięgu blokowym. Pozwala na późniejszą modyfikację wartości.
Przykład:
let liczba: number = 5;
liczba = 10;
- const
Deklaruje stałe (niemodyfikowalne) zmienne o zasięgu blokowym. Po przypisaniu wartości nie można jej zmienić.
Przykład:
const tekst: string = "Hello, World!";
// tekst = "Zmiana"; // spowoduje błąd kompilacji
- var
Deklaruje zmienne o zasięgu funkcyjnym. Jest mniej zalecany z uwagi na problemy z hoistingiem oraz potencjalnymi nieprzewidywalnymi efektami w zasięgu blokowym.
Przykład:
var zmienna: number = 15;
zmienna = 20;
Dla szczegółowych informacji na temat różnic między tymi deklaracjami, możesz zapoznać się z artykułem Zasięg (scope) w JavaScript i TypeScript.
Czym jest wnioskowanie typów (type inference) i jakie są jego zalety?
TypeScript potrafi automatycznie wywnioskować typy zmiennych na podstawie przypisanych wartości. Dzięki temu nie musimy jawnie określać typu dla każdej zmiennej, co zwiększa czytelność kodu i zmniejsza nadmiarowość anotacji typów. Zalety wnioskowania typów to:
- Redukcja ilości kodu – mniejsza liczba jawnych deklaracji.
- Bezpieczeństwo typów – kompilator nadal jest w stanie sprawdzać poprawność typów, co zapobiega wielu potencjalnym błędom.
- Lepsza czytelność – kod jest bardziej zwięzły i łatwiejszy do utrzymania.
Przykład:
let wiek = 30; // TypeScript wnioskuje, że 'wiek' ma typ number
wiek = 31;
// wiek = "trzydzieści jeden"; // spowoduje błąd kompilacji, ponieważ typ string jest niezgodny z typem number
Więcej o wnioskowaniu typów znajdziesz w oficjalnej dokumentacji TypeScript – Type Inference.
Jak deklarować i używać tzw. "tuple" w TypeScript?
Tuple (krotki) pozwalają na przechowywanie zestawu elementów o różnych typach w jednej zmiennej. Definiuje się je przez określenie kolejnych typów elementów w tablicy.
Przykład deklaracji krotki:
let osoba: [string, number] = ["Jan Kowalski", 30];
Tutaj element pierwszy (imię i nazwisko) jest typu string, a element drugi (wiek) jest typu number.
Krotki są szczególnie przydatne, gdy chcemy, aby dane miały ściśle określoną strukturę, np. wyniki funkcji zwracające wiele wartości o różnych typach.
Dalsze informacje na temat krotek znajdują się w dokumentacji TypeScript – Tuple Types.
W jaki sposób definiować typ enum i w jakich sytuacjach warto go stosować?
enum umożliwia definiowanie zestawu nazwanych stałych, co zwiększa czytelność i utrzymanie kodu. W TypeScript enums mogą być numeryczne (domyślne) lub łańcuchowe (string enums).
Przykład numerycznego enum:
enum Kolor {
Czerwony, // domyślnie 0
Zielony, // 1
Niebieski, // 2
}
let wybranyKolor: Kolor = Kolor.Zielony;
Przykład enum z wartościami łańcuchowymi:
enum Kierunek {
Północ = "POLNOC",
Południe = "POLUDNIE",
Wschód = "WSCHOD",
Zachód = "ZACHOD"
}
let kierunekPodrozy: Kierunek = Kierunek.Wschód;
Enums są szczególnie przydatne, gdy zestaw dozwolonych wartości jest z góry ustalony i niezmienny, np. dni tygodnia, stany w aplikacji lub kierunki ruchu.
Więcej informacji na temat enums znajdziesz w dokumentacji TypeScript – Enums.
Funkcje i klasy
Jak definiować funkcje w TypeScript z uwzględnieniem określania typów argumentów i zwracanego typu?
W TypeScript funkcje definiujemy podobnie jak w JavaScript, ale dodając adnotacje typów dla argumentów oraz typu zwracanego. Przykład definicji funkcji:
function dodaj(a: number, b: number): number {
return a + b;
}
Tutaj:
- Typy
numberprzy argumentachaibokreślają, że funkcja przyjmuje liczby. - Adnotacja
: numberpo nawiasach funkcji oznacza typ zwracanego wyniku.
Materiał do pogłębienia tematu:
Oficjalny podręcznik TypeScript – Functions
Co to są funkcje strzałkowe i jak różnią się od tradycyjnych funkcji?
Funkcje strzałkowe to krótsza składnia funkcji wprowadzona w ES6. Różnią się od tradycyjnych funkcji głównie sposobem wiązania kontekstu (this):
- Funkcje strzałkowe nie posiadają własnego kontekstu
this– dziedziczą go z otaczającego kontekstu. - Składnia jest bardziej zwięzła, co ułatwia pisanie krótkich funkcji.
Przykład funkcji strzałkowej:
const mnoz = (a: number, b: number): number => a * b;
Dla porównania, tradycyjna funkcja wyglądałaby następująco:
function mnoz(a: number, b: number): number {
return a * b;
}
Materiał do pogłębienia tematu:
MDN – Funkcje strzałkowe (polska wersja)
Jakie mechanizmy wsparcia oferuje TypeScript dla programowania obiektowego (klasy, dziedziczenie, interfejsy)?
TypeScript rozszerza możliwości JavaScript o pełne wsparcie dla programowania obiektowego. Obejmuje to między innymi:
- Klasy: Pozwalają definiować szablony obiektów. Możemy w nich definiować właściwości, metody oraz konstruktory.
- Dziedziczenie: Klasy mogą rozszerzać inne klasy przy użyciu słowa kluczowego
extends, co umożliwia ponowne wykorzystanie i rozszerzenie funkcjonalności. - Interfejsy: Umożliwiają definiowanie kontraktów, które muszą spełniać klasy lub obiekty, co poprawia spójność i typowanie kodu.
Przykład klasy z interfejsem:
interface IPunkt {
x: number;
y: number;
}
class Punkt implements IPunkt {
constructor(public x: number, public y: number) {}
}
class KolorowyPunkt extends Punkt {
constructor(x: number, y: number, public kolor: string) {
super(x, y);
}
}
Materiał do pogłębienia tematu:
Oficjalny podręcznik TypeScript – Klasy
W jaki sposób wykorzystać modifier’y dostępu (public, private, protected) przy definiowaniu klas?
W TypeScript dostępne są trzy główne modyfikatory dostępu:
- public: Elementy oznaczone jako public są dostępne wszędzie. Domyślnie wszystkie właściwości i metody klasy są publiczne.
- private: Elementy prywatne są dostępne tylko wewnątrz definicji danej klasy. Nie można ich odwołać z poziomu instancji ani podklas.
- protected: Elementy chronione są dostępne wewnątrz klasy bazowej oraz jej podklas, ale nie są dostępne na zewnątrz.
Przykład użycia:
class Samochod {
public marka: string;
private numerVin: string;
protected model: string;
constructor(marka: string, model: string, numerVin: string) {
this.marka = marka;
this.model = model;
this.numerVin = numerVin;
}
public wyswietlInfo(): void {
console.log(`Marka: ${this.marka}, Model: ${this.model}`);
}
}
class SportowySamochod extends Samochod {
public turbo: boolean;
constructor(marka: string, model: string, numerVin: string, turbo: boolean) {
super(marka, model, numerVin);
this.turbo = turbo;
}
public wyswietlInfo(): void {
// Dostęp do chronionego pola 'model' jest możliwy
console.log(`Marka: ${this.marka}, Model: ${this.model}, Turbo: ${this.turbo}`);
}
}
Materiał do pogłębienia tematu:
Oficjalny podręcznik TypeScript – Klasy i modyfikatory dostępu
Jak zrealizować przeciążanie funkcji (function overloading) w TypeScript?
TypeScript umożliwia definiowanie wielu sygnatur funkcji, co nazywamy przeciążaniem funkcji. Najpierw deklarujemy kilka sygnatur, a następnie implementujemy funkcję, która obsługuje wszystkie warianty. Przykład:
// Definicje przeciążone
function przetworz(tekst: string): string;
function przetworz(liczba: number): number;
// Implementacja funkcji
function przetworz(param: string | number): string | number {
if (typeof param === "string") {
return param.toUpperCase();
} else {
return param * 2;
}
}
// Użycie
console.log(przetworz("hello")); // "HELLO"
console.log(przetworz(5)); // 10
Materiał do pogłębienia tematu:
Oficjalny podręcznik TypeScript – Przeciążanie funkcji
Zaawansowane typy i funkcje
Jak działają generyki w TypeScript i dlaczego są ważnym narzędziem w tworzeniu elastycznych komponentów?
Generyki w TypeScript umożliwiają definiowanie funkcji, klas czy interfejsów, które mogą operować na danych o różnych typach, przy zachowaniu pełnej kontroli nad typami w czasie kompilacji. Pozwala to na tworzenie elastycznych i wielokrotnego użytku komponentów, które są jednocześnie bezpieczne typowo. Dzięki generykom można uniknąć powielania kodu oraz minimalizować błędy związane z nieprawidłowym użyciem typów, co przekłada się na bardziej wydajny i czytelny kod.
Źródła:
Co reprezentuje typ any, a jakie są jego potencjalne zagrożenia?
Typ any w TypeScript oznacza, że nie jest stosowana żadna szczegółowa kontrola typów. Użycie tego typu pozwala na przypisanie do zmiennej wartości dowolnego typu, co może prowadzić do utraty korzyści płynących z systemu typów. Główne zagrożenia to:
- Brak bezpieczeństwa typów: Błędy, które mogłyby być wykryte podczas kompilacji, zostaną wykryte dopiero w trakcie wykonywania aplikacji.
- Utrudniona konserwacja kodu: Zbyt częste stosowanie typu
anyzmniejsza czytelność kodu i może prowadzić do trudności w odnalezieniu błędów podczas rozwoju projektu.
Źródła:
Czym jest typ unknown i kiedy warto go używać?
Typ unknown został wprowadzony jako bezpieczniejsza alternatywa dla typu any. Podobnie jak any może reprezentować dowolną wartość, jednakże operacje na zmiennych typu unknown wymagają uprzedniej weryfikacji typu lub użycia mechanizmów zawężających typ (ang. type narrowing). Stosowanie typu unknown jest zalecane, gdy nie mamy pewności co do typu wartości, ale chcemy zachować pełną kontrolę nad jej przetwarzaniem, co zwiększa bezpieczeństwo aplikacji.
Źródła:
Jak działają typy przecięcia (intersection types) i typy unii (union types)?
Typy przecięcia (intersection types):
Umożliwiają łączenie kilku typów w jeden, dzięki czemu obiekt musi spełniać wszystkie warunki określonych typów. Jest to przydatne, gdy chcemy połączyć cechy kilku typów w jeden kompleksowy typ.
Typy unii (union types):
Pozwalają na określenie, że zmienna może przyjmować wartości z jednego z wielu określonych typów. Dzięki nim można operować na zmiennych, których typy są z góry zdefiniowane jako jedna z możliwych opcji, co zwiększa elastyczność kodu.
Źródła:
Jak implementować typy warunkowe (conditional types) oraz mapowanie typów (mapped types) w praktyce?
Typy warunkowe (conditional types):
Pozwalają na wybór jednego z dwóch typów na podstawie spełnienia określonego warunku. Składnia przypomina konstrukcję warunkową if-else w typach. Umożliwia dynamiczne określanie typu na podstawie relacji między typami wejściowymi.
Mapowanie typów (mapped types):
Służą do transformowania typów poprzez iterację po kluczach danego typu i modyfikację przypisanych do nich typów. Dzięki temu można w łatwy sposób tworzyć nowe typy na bazie istniejących, np. poprzez oznaczanie wszystkich właściwości jako opcjonalne lub wymagane.
Implementacja tych mechanizmów umożliwia tworzenie bardziej dynamicznych i abstrakcyjnych definicji typów, co jest szczególnie przydatne w dużych projektach, gdzie zachowanie spójności typów jest kluczowe.
Źródła:
Jakie są ograniczenia (constraints) podczas definiowania parametrów typów w generykach?
Ograniczenia parametrów typów (constraints) w generykach służą do ograniczenia możliwych wartości, jakie mogą przyjmować parametry typu. Stosuje się je za pomocą słowa kluczowego extends, co pozwala na określenie, że parametr typu musi być zgodny z określonym typem lub posiadać określone właściwości. Dzięki temu możemy wymusić poprawność typów w kodzie oraz zapewnić, że tylko odpowiednie rodzaje wartości zostaną użyte w generycznych konstrukcjach. Jest to szczególnie przydatne, kiedy operujemy na obiektach, które muszą implementować określone interfejsy lub posiadać konkretne właściwości.
Źródła:
Moduły i systemy modułów
Odpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedzimodule w pliku konfiguracyjnym tsconfig.json?
Odpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziPraktyki najlepsze i wzorce projektowe
Odpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziIntegracja z frameworkami fullstack
Odpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedziOdpowiedź dostępna w pełnej wersji. Odblokuj 30 pozostałych odpowiedzi i ucz się z pełnego zestawu.
Odblokuj odpowiedzi