JavaScript jest językiem dynamicznie typowanym, więc typ zmiennej może zmieniać się w trakcie działania programu. Aby pisać bezpieczny, przewidywalny kod w większych aplikacjach, musisz umieć sprawdzać typ wartości w runtime. Najczęściej robi się to dwoma operatorami: typeof i instanceof.
Choć oba „dotyczą typów”, rozwiązują różne problemy i stosuje się je w innych sytuacjach. Poniżej szczegółowo wyjaśniam:
- co dokładnie robi
typeof, - co dokładnie robi
instanceof, - jakie są ich ograniczenia i pułapki,
- którego używać w jakich scenariuszach (z praktycznymi przykładami),
- jakie są alternatywy dla bardziej precyzyjnego sprawdzania typów.
1. Krótkie przypomnienie – typy w JavaScript
Typy prymitywne: string, number, boolean, undefined, symbol, bigint oraz specjalny null (też prymityw, ale z historycznym „bugiem” w typeof).
Typy obiektowe: wszystko inne, m.in. obiekty {}, tablice [], funkcje, Date, RegExp, Error, instancje klas własnych.
typeof najlepiej nadaje się do prymitywów i funkcji.
instanceof działa tylko na obiektach i sprawdza ich łańcuch prototypów.
2. Operator typeof – co robi i do czego się nadaje?
Definicja i składnia
typeof to operator jednoargumentowy, który zwraca łańcuch znaków opisujący typ wartości podanej jako operand. Składnia:
typeof wyrazenie
Przykłady użycia:
typeof 42; // "number"
typeof 'tekst'; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof 10n; // "bigint"
Możliwe zwroty to m.in.: "undefined", "boolean", "number", "string", "object", "function", "symbol", "bigint".
Cechy kluczowe:
- zwraca string opisujący typ,
- działa świetnie dla typów prymitywnych,
- pozwala sprawdzić, czy coś jest funkcją (
typeof fn === 'function').
Typowe zastosowania typeof
Najczęstsze przypadki użycia:
- Sprawdzanie typów prymitywnych
Kod:
function formatPrice(value) {
if (typeof value !== 'number') {
throw new TypeError('value must be a number');
}
return value.toFixed(2) + ' zł';
}
Dla prymitywów dokumentacja wprost zaleca typeof.
- Bezpieczne sprawdzanie, czy zmienna jest niezdefiniowana
Kod:
if (typeof someGlobalVariable === 'undefined') {
// zmienna nie jest zdefiniowana
}
- Sprawdzanie, czy coś jest funkcją
Kod:
if (typeof callback === 'function') {
callback();
}
Ograniczenia i „dziwactwa” typeof
typeof null === 'object' – historyczny bug
typeof null zwraca "object", co jest znanym historycznym błędem w specyfikacji. Kod:
typeof null; // "object"
Nie używaj typeof do odróżniania null od obiektów. Do tego sprawdzaj wprost: value === null.
Tablice, daty, RegExp – wszystko wygląda jak „object”
W przypadku wielu złożonych typów typeof zwraca wyłącznie "object". Kod:
typeof []; // "object"
typeof new Date(); // "object"
typeof /abc/; // "object"
Nie rozpoznasz tablicy za pomocą typeof. Użyj Array.isArray().
Nie odróżnisz Date od zwykłego obiektu. Użyj instanceof Date.
Brak informacji o konkretnym typie obiektu
typeof nie powie, czy to Array / Date / własna klasa – wskaże tylko, czy to prymityw, obiekt lub funkcja.
3. Operator instanceof – co robi i jak działa?
Definicja i składnia
instanceof sprawdza, czy dany obiekt jest instancją podanego konstruktora/klasy. Składnia:
obj instanceof Constructor
Przykład:
const arr = [];
arr instanceof Array; // true
arr instanceof Object; // true
Wewnątrz sprawdzane jest, czy Constructor.prototype występuje w łańcuchu prototypów obiektu.
Jak instanceof działa „pod maską”?
Po pierwsze, porównuje Constructor.prototype z kolejnymi prototypami w łańcuchu obiektu. Po drugie, jeśli znajdzie dopasowanie – zwraca true, w przeciwnym razie false.
Można też nadpisać zachowanie za pomocą Symbol.hasInstance. Przykład:
class EvenNumber {
static [Symbol.hasInstance](instance) {
return typeof instance === 'number' && instance % 2 === 0;
}
}
2 instanceof EvenNumber; // true
3 instanceof EvenNumber; // false
instanceof działa tylko na obiektach
Próby użycia z prymitywami zwrócą false. Kod:
42 instanceof Number; // false (bo 42 jest prymitywem)
'tekst' instanceof String; // false
Dla typów obiektowych:
new Number(42) instanceof Number; // true
new Number(42) instanceof Object; // true
Wszystkie nieprymitywne obiekty są instancjami Object:
({}) instanceof Object; // true
[] instanceof Object; // true
new Date() instanceof Object; // true
Typowe zastosowania instanceof
Gdzie sprawdza się najlepiej:
- Sprawdzanie typu obiektowego (klasy/konstruktora)
Kod:
class User {}
const u = new User();
u instanceof User; // true
u instanceof Object; // true
- Rozpoznawanie wbudowanych klas obiektowych (
Array,Date,RegExp,Error)
Kod:
const arr = [1, 2, 3];
arr instanceof Array; // true
arr instanceof Object; // true
const d = new Date();
d instanceof Date; // true
d instanceof Object; // true
- Dziedziczenie i polimorfizm
Kod:
class Animal {}
class Dog extends Animal {}
const d = new Dog();
d instanceof Dog; // true
d instanceof Animal; // true
d instanceof Object; // true
4. typeof vs instanceof – zasadnicze różnice
Poniższa tabela zbiera najważniejsze różnice w jednym miejscu:
| Cecha | typeof |
instanceof |
|---|---|---|
| Co sprawdza | rodzaj wartości (prymityw/obiekt/funkcja) | czy obiekt jest instancją konstruktora/klasy |
| Zwracany typ | string (np. "number", "object") |
boolean (true/false) |
| Główne zastosowanie | typy prymitywne + funkcje | obiekty, klasy, konstruktory |
| Mechanizm działania | analizuje samą wartość | sprawdza łańcuch prototypów obiektu |
| Praca z prymitywami | tak (idealny do prymitywów) | nie (prymitywy nie są instancjami klas) |
| Rozpoznawanie klas/typów obiektowych | ograniczone (większość to "object") |
dokładne: obj instanceof Array/Date/CustomClass |
| Przykład użycia | typeof value === 'string' |
value instanceof Date |
Reguła kciuka: używaj typeof do prymitywów i funkcji, a instanceof do obiektów i klas.
5. Praktyczne scenariusze – kiedy używać którego?
Walidacja wejścia funkcji
Przykład 1 – oczekujemy liczby
Kod:
function calculateVAT(amount) {
if (typeof amount !== 'number') { // ✅ typeof – prymityw
throw new TypeError('amount must be a number');
}
return amount * 0.23;
}
Tutaj:
- interesuje nas typ prymitywny (
number), - nie ma żadnej klasy/konstruktora,
typeofjest naturalnym wyborem.
Przykład 2 – oczekujemy tablicy
Kod:
function sum(values) {
if (!Array.isArray(values)) { // ✅ Array.isArray – lepsze niż instanceof / typeof
throw new TypeError('values must be an array');
}
return values.reduce((a, b) => a + b, 0);
}
Dlaczego nie typeof? Bo typeof values zwróci "object" i nie odróżni tablicy od innych obiektów.
Dlaczego nie instanceof Array? Choć często zadziała, Array.isArray() jest dedykowaną i bardziej odporną metodą (różne środowiska, ramki iframe itd.).
Sprawdzanie, czy funkcja została przekazana jako callback
Kod:
function runCallback(callback) {
if (typeof callback !== 'function') { // ✅ typeof – funkcje
throw new TypeError('callback must be a function');
}
callback();
}
typeof zwraca "function" dla funkcji, co jest powszechnie wykorzystywane.
Praca z datami (Date)
Kod:
function formatDate(value) {
if (!(value instanceof Date)) { // ✅ instanceof – konkretny typ obiektowy
throw new TypeError('value must be a Date');
}
return value.toISOString();
}
Tutaj:
- potrzebujemy konkretnego typu obiektowego (
Date), typeof valuezwróci tylko"object",value instanceof Datedaje precyzyjną informację, czy obiekt jest datą.
Praca z błędami (Error)
Kod:
try {
// ...
} catch (err) {
if (err instanceof TypeError) { // ✅ instanceof – hierarchia błędów
console.error('Type error:', err.message);
} else if (err instanceof Error) {
console.error('Other error:', err.message);
} else {
console.error('Unknown problem', err);
}
}
instanceof świetnie sprawdza się tam, gdzie ważna jest hierarchia typów (np. różne klasy błędów).
Własne klasy i obiekty domenowe
Kod:
class User {}
class Admin extends User {}
function isAdmin(user) {
return user instanceof Admin; // ✅ instanceof – własna klasa
}
Przy własnych obiektach i klasach instanceof pozwala dokładnie określić konstruktor użyty do stworzenia obiektu.
Sprawdzanie, czy coś jest zdefiniowane
Kod:
if (typeof window !== 'undefined') { // ✅ typeof – bezpieczne sprawdzanie globali
// kod tylko dla przeglądarki
}
typeof nie rzuca błędu, jeśli nazwa nie została zadeklarowana, dlatego nadaje się do sprawdzania globali.
6. Alternatywy i uzupełnienia dla typeof i instanceof
Array.isArray()
Dla tablic używaj metody dedykowanej. Kod:
Array.isArray([]); // true
Array.isArray({}); // false
Object.prototype.toString.call
Gdy potrzebujesz precyzyjnego stringa typu (dla prymitywów i obiektów), skorzystaj z:
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(new Date()); // "[object Date]"
Inne metody wbudowane
Przydatne uzupełnienia:
- Number.isNaN – lepsze niż stare
isNaN; - Number.isInteger – sprawdza, czy liczba jest całkowita;
- RegExp –
value instanceof RegExpdo wykrycia wyrażeń regularnych; - bigint –
typeof value === 'bigint'do dużych liczb.
7. Dobre praktyki – jak używać typeof i instanceof w nowoczesnym kodzie
- Dla typów prymitywnych (
string,number,boolean,undefined,symbol,bigint) używajtypeof.
Kod:
if (typeof value === 'string') {
// ...
}
- Do sprawdzania funkcji (
callback,handler) używajtypeof value === 'function'. - Do obiektów, klas i konstruktorów (w tym własnych) używaj
instanceof.
Kod:
if (obj instanceof MyClass) {
// ...
}
- Nie polegaj na
typeofdla złożonych obiektów (tablice, daty,RegExp) – zwróci tylko"object". - Nie ufaj
typeof null– zawsze daje"object". Sprawdzajvalue === null. - Dla tablic preferuj
Array.isArray()zamiastinstanceof Arrayczytypeof. - Gdy potrzebujesz stringowej nazwy typu (np. w logowaniu), rozważ:
Kod:
const type = Object.prototype.toString.call(value);
- Projektując API/komponenty, waliduj typy wejściowe – stosuj właściwe narzędzia do właściwych typów:
- prymitywy →
typeof, - obiekty domenowe →
instanceof, - kolekcje specjalne → metody dedykowane (np.
Array.isArray).
- Pamiętaj, że
instanceofopiera się na łańcuchu prototypów – jego nietypowa modyfikacja może prowadzić do nieintuicyjnych wyników.
8. Dlaczego poprawne sprawdzanie typów jest ważne także dla dostępności?
W aplikacjach webowych dbających o dostępność warto pilnować typów, bo:
- atrybuty ARIA, role, etykiety i wartości stanu często muszą być konkretnymi typami (ciągi znaków, wartości logiczne),
- błędna walidacja typów może powodować:
- brak ustawienia odpowiedniej etykiety,
- wyświetlenie błędnego komunikatu o błędzie,
- przerwanie obsługi klawiatury lub czytnika ekranu.
Dlatego przy budowie komponentów dostępnych (formularze, dialogi, nawigacja) warto konsekwentnie używać właściwych narzędzi:
typeofdo weryfikacji prymitywów w propsach/konfiguracji,instanceofdo weryfikacji obiektów odpowiedzialnych za stan i zdarzenia,- metody dedykowane (np.
Array.isArray()) dla kolekcji.
Poprawne użycie typeof i instanceof pozwala wykryć błędy wcześniej – na etapie implementacji, a nie dopiero w testach dostępności.






