У TypeScript існує кілька способів описувати об’єкти: за допомогою інтерфейсів, типів, класів або простих об’єктних літералів. Також окрім цих підходів, є ще вбудований базовий тип – object.
У цьому дописі ми розберемо:
- що саме означає тип object
- чим він відрізняється від інших способів опису об’єктів
- коли його варто застосовувати на практиці
Що таке object?
Тип object у TypeScript представляє всі значення, які не є примітивами.
До примітивних типів у JavaScript належать: string, number, boolean, bigint, symbol, null, undefined.
Приклади значень, які підпадають під тип object:
let a: object;
a = { name: 'Alex' }; // ok
a = [1, 2, 3]; // ok
a = new Date(); // ok
a = 'hello'; // Error: Type 'string' is not assignable to type 'object'
a = 42; // Error: Type 'number' is not assignable to type 'object'Таким чином, object – це узагальнюючий тип для всіх непримітивних значень у JavaScript.
Важливі відмінності
1. object vs {}
Тип object дозволяє лише непримітивні значення, тоді як {} (порожній об’єктний тип) – дозволяє будь-що, окрім null і undefined:
let x: {};
x = 10; // ok
x = 'text'; // ok
x = { a: 1 }; // ok
let y: object;
y = 10; // error
y = { a: 1 }; // okТобто {} у TypeScript фактично означає «будь-яке значення, крім null та undefined», тоді як object – лише «непримітиви».
2. object vs Object
Тип object було введено у TypeScript 2.2 саме для точнішого опису непримітивних значень. Натомість Object (з великої літери) – це глобальний тип JavaScript, який охоплює навіть примітиви, оскільки в JS кожен примітив може бути обгорнутий у об’єкт (наприклад, new String('abc')):
let a: Object;
a = 42; // ok
a = 'hello'; // ok
a = { key: 1 }; // ok
let b: object;
b = 42; // error
b = { key: 1 }; // okНа практиці краще використовувати object, оскільки він обмежує тип лише непримітивами і запобігає помилкам типізації. Тип Object менш строгий і зазвичай не потрібен.
3. object vs Record<string, unknown>
Тип object не дозволяє звертатись до властивостей без додаткової перевірки або кастингу. Якщо потрібно явно описати «об’єкт з довільними ключами», краще використовувати Record<string, unknown>:
let obj: object = { name: 'Alex' };
console.log(obj.name); // Error: Property 'name' does not exist on type 'object'
// потрібен кастинг (type assertion)
console.log((obj as { name: string }).name);Натомість Record<string, unknown> дозволяє звертатись до властивостей, але змушує уточнювати тип значення:
let record: Record<string, unknown> = { name: 'Alex' };
// Можна звернутися до властивості але треба уточнювати тип
console.log(record['name'].toUpperCase()); // Error: Object is of type 'unknown'
// потрібна перевірка типу
if (typeof record['name'] === 'string') {
console.log(record['name'].toUpperCase());
}Таким чином:
- object – це будь-який не примітив, але структура невідома
- Record<string, unknown> – це об’єкт з рядковими ключами, доступними для звернення, але тип значень потрібно уточнювати
Практичні випадки використання
Тип object застосовують у ситуаціях, коли потрібно працювати з будь-якими непримітивними значеннями, але точна структура об’єкта не має значення. Це зручно, якщо функція або змінна мають приймати будь-який об’єктоподібний тип (наприклад, Object, Array, Map, Date тощо).
Приклад:
function logObject(value: object) {
console.log('Got object:', value);
}
logObject([1, 2, 3]); // ok
logObject({ a: 1, b: 2 }); // ok
logObject(new Date()); // ok
logObject('hello'); // error
logObject(42); // errorПідсумок
Тип object у TypeScript корисний тоді, коли потрібно відсіяти примітиви, при цьому точна форма об’єкта не має значення.
Якщо ж потрібно описати об’єкти з певними властивостями або ключами, краще використовувати більш точні типи – інтерфейси, власні типи або Record.