Developer wearing protective glasses focuses on code across dual wide screen monitors in dim office

Operatory typeof i instanceof w JavaScript – kiedy stosować każdy?

8 min. czytania

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:

  1. 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.

  1. Bezpieczne sprawdzanie, czy zmienna jest niezdefiniowana

Kod:

if (typeof someGlobalVariable === 'undefined') {
// zmienna nie jest zdefiniowana
}

  1. 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:

  1. Sprawdzanie typu obiektowego (klasy/konstruktora)

Kod:

class User {}
const u = new User();

u instanceof User; // true
u instanceof Object; // true

  1. 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

  1. 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,
  • typeof jest 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 value zwróci tylko "object",
  • value instanceof Date daje 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;
  • RegExpvalue instanceof RegExp do wykrycia wyrażeń regularnych;
  • biginttypeof value === 'bigint' do dużych liczb.

7. Dobre praktyki – jak używać typeof i instanceof w nowoczesnym kodzie

  1. Dla typów prymitywnych (string, number, boolean, undefined, symbol, bigint) używaj typeof.

Kod:

if (typeof value === 'string') {
// ...
}

  1. Do sprawdzania funkcji (callback, handler) używaj typeof value === 'function'.
  2. Do obiektów, klas i konstruktorów (w tym własnych) używaj instanceof.

Kod:

if (obj instanceof MyClass) {
// ...
}

  1. Nie polegaj na typeof dla złożonych obiektów (tablice, daty, RegExp) – zwróci tylko "object".
  2. Nie ufaj typeof null – zawsze daje "object". Sprawdzaj value === null.
  3. Dla tablic preferuj Array.isArray() zamiast instanceof Array czy typeof.
  4. Gdy potrzebujesz stringowej nazwy typu (np. w logowaniu), rozważ:

Kod:

const type = Object.prototype.toString.call(value);

  1. 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).
  1. Pamiętaj, że instanceof opiera 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:

  • typeof do weryfikacji prymitywów w propsach/konfiguracji,
  • instanceof do 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.