#4 Інтерфейси та типи обʼєктів, створення, наслідування, різниця з type

Інтерефейси в TS це тіж самі типи, але створення для обʼєктів. Коли ви створюєете обʼєкт, ви повинні створити також інтерфейс, в якому будуть зазначені всі типи для всіх ключів.

Базовий приклад:

interface User {
    name: string;
    age: number;
    isActive: boolean;
}

const user: User = {
    name: "Олександр",
    age: 30,
    isActive: true,
};

console.log(user.name); // Олександр

Також в інтерфейсах є один нюанс, вам потрібно зазнчати всі значення, які використовуються, та ви не можете залишити їх пустими. Тобто, якщо в інтерфейсі ви вказали age, то поле age обовʼязково повинно бути в обʼєкті. І навпаки, якщо ви щось не вказали в інтерфейсі, то його не може бути в обʼєкті. Для вирішення цієї проблеми є спеціальний оператор - ?.

interface User {
    name: string;
    glory: string | number | null,
    age?: number; // Може бути відсутнім
}

const user: User = {
    name: "Анна",
    glory: 25
};

console.log(user.age); // undefined

Readonly

Я вважаю що це перша користна властивість. Звістно, в звичайному JS ви також можете використовувати object prototype freeze, або аналоги, але тут це робиться однією строчкою. Ви можете визначати ключі, які не можна буде змінювати.

interface User {
    readonly id: number;
    name: string;
}

const user: User = {
    id: 1,
    name: "Олексій",
};

// user.id = 2; // Помилка: властивість лише для читання
console.log(user.id); // 1

Функції в інтерфейсах

Щодо функцій в інтерфейсах, то ва також треба буде зазначати в них параметри, а також те, що вони повертають. Це можна зробити ось так:

interface Calculator {
    add(a: number, b: number): number;
    subtract(a: number, b: number): number;
}

const calculator: Calculator = {
    add: (a, b) => a + b,
    subtract: (a, b) => a - b,
};

console.log(calculator.add(5, 3)); // 8

В принципі, як я казав уже раніше, весь тайпскрипт, це про додавання типізації до будь чого. Тобто перетворення динамічного JS, в статичний С мабуть.

Індексовані типи

Індексовані типи, це коли у вас в обʼєкті може бути багато невизначених типів, але всі вони повинні належати до якогось типу. Це можна реалізувати ось так:

interface UserDictionary {
    [key: string]: string; // Індексовані значення
    admin: number; // Конкретна властивість
}

const users: UserDictionary = {
    admin: 35,
    editor: "Анна",
    guest: "Іван",
};

console.log(users.admin); // 35
console.log(users.editor); // Анна

Динамічні ключі 

Це коли вам потрібно створити тип, динамічний тип, чи данмічне значення, тоді можна використати Record, в якому ви можете перерахувати ключі, та динамічні значення приклад:

type RoleDictionary = Record<"admin" | "editor" | "guest", string | number>;

const roles: RoleDictionary = {
    admin: "Адміністратор",
    editor: "Редактор",
    guest: "Гість",
};

console.log(roles.admin); // Адміністратор 

Іморт інтерфейсів

Думаю це одне з самих головних рішень. Трохи пізніше ми розберемо, як налаштовувати автоімпорт інтерфейсів, але зараз я покажу я просто зробити імпорт. Інтерфейси по факту можна экспортувати як звичайні змінні:

// interfaces.ts
export interface User {
    id: number;
    name: string;
    email: string;
}

export interface Product {
    id: number;
    title: string;
    price: number;
}


// index.ts
import { User, Product } from './interfaces';

const user: User = {
    id: 1,
    name: "Олексій",
    email: "oleksii@example.com",
};

const product: Product = {
    id: 101,
    title: "Ноутбук",
    price: 25000,
};

І коли ми дошли до імпорта, мабуть постало логічне питання, а як розширювати інтерфейси, якщо для якогось конкретного модуля, це стало необхідним:

interface Person {
    name: string;
    age: number;
}

interface Employee extends Person {
    position: string;
}

const employee: Employee = {
    name: "Марія",
    age: 28,
    position: "Менеджер",
};

console.log(employee.position); // Менеджер

Тут все дуже просто, ви можете прописати, або імпортувати будь який інтерфейс, і після розиширити його, за домогою extends в новий інтерфейс, наприклад Employee.

І це також чудово працює з імпортами:

import { User } from './interfaces.ts';

interface Employee extends User {
  position: string;
}

const user: Employee = {
  id: 1,
  name: "Олексій",
  email: "oleksii@example.com",
  position: "adwawd"
};

На цьому мабуть все, побачимося в наступному уроці