Легкийtypesprimitivesbasictypingbest-practices

Які основні типи даних є в TypeScript?

Детальний огляд базових типів даних TypeScript та їх практичне використання

Які основні типи даних є в TypeScript?

TypeScript надає багатий набір типів даних, які допомагають створювати більш надійний та передбачуваний код. Розуміння цих типів - основа для ефективної роботи з TypeScript.

Type Annotations vs Type Inference

TypeScript може автоматично визначати типи (inference) або ви можете явно вказувати їх (annotations):

// Type inference - TypeScript сам визначає тип
let name = "Олександр"; // string
let age = 25; // number

// Type annotations - ми явно вказуємо тип
let name: string = "Олександр";
let age: number = 25;

Коли використовувати: Використовуйте type annotations коли TypeScript не може визначити тип автоматично або для покращення читабельності коду.

Примітивні типи

Boolean

Логічний тип з двома можливими значеннями:

let isDone: boolean = false;
let isActive: boolean = true;
let isLoading: boolean = false;

// Практичний приклад
function toggleMenu(isOpen: boolean): boolean {
    return !isOpen;
}

// У функціональних компонентах
const [isVisible, setIsVisible] = useState<boolean>(false);

Best practice: Завжди ініціалізуйте boolean змінні явним значенням.

Number

Усі числа в TypeScript є числами з плаваючою точкою:

// Різні формати чисел
let decimal: number = 42;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let float: number = 3.14;
let negative: number = -10;

// Спеціальні числові значення
let infinity: number = Infinity;
let notANumber: number = NaN;

// Практичні приклади
function calculatePrice(price: number, tax: number): number {
    return price + (price * tax / 100);
}

function isEven(num: number): boolean {
    return num % 2 === 0;
}

Best practice: Використовуйте number для всіх числових значень. TypeScript не розрізняє цілі числа та числа з плаваючою точкою.

String

Текстові дані з підтримкою template literals:

let color: string = "синій";
let firstName: string = 'Олена';

// Template literals (рекомендовано)
let fullName: string = `${firstName} Коваленко`;
let age: number = 28;
let greeting: string = `Привіт! Мене звати ${fullName} і мені ${age} років.`;

// Багаторядкові рядки
let multiline: string = `
    Це багаторядковий
    рядок в TypeScript
`;

// Практичні приклади
function formatCurrency(amount: number, currency: string = "UAH"): string {
    return `${amount} ${currency}`;
}

function createSlug(title: string): string {
    return title.toLowerCase().replace(/\s+/g, '-');
}

Best practice: Використовуйте template literals для конкатенації рядків та багаторядкових текстів.

Array

Колекції елементів одного типу:

// Два способи оголошення масивів
let numbers: number[] = [1, 2, 3, 4, 5];
let strings: Array<string> = ["apple", "banana", "orange"];

// Масиви об'єктів
interface User {
    id: number;
    name: string;
}

let users: User[] = [
    { id: 1, name: "Олег" },
    { id: 2, name: "Марія" }
];

// Практичні методи роботи з масивами
function getEvenNumbers(numbers: number[]): number[] {
    return numbers.filter(num => num % 2 === 0);
}

function findUserById(users: User[], id: number): User | undefined {
    return users.find(user => user.id === id);
}

// Readonly масиви
let readonlyNumbers: readonly number[] = [1, 2, 3];
// readonlyNumbers.push(4); // Помилка!

Best practice: Віддавайте перевагу синтаксису type[] над Array<type> для простіших типів.

Літеральні типи

Точні значення як типи:

// String literals
let direction: "left" | "right" | "up" | "down" = "left";

// Number literals
let diceRoll: 1 | 2 | 3 | 4 | 5 | 6 = 3;

// Boolean literals
let isTrue: true = true;

// Практичний приклад
type Theme = "light" | "dark" | "auto";
type Size = "small" | "medium" | "large";

interface ButtonProps {
    theme: Theme;
    size: Size;
    disabled: boolean;
}

function createButton(props: ButtonProps): void {
    // логіка створення кнопки
}

Спеціальні типи

Any

Відключає перевірку типів (використовуйте обережно):

let notSure: any = 4;
notSure = "може бути рядком";
notSure = false;
notSure.toUpperCase(); // Не буде помилки компіляції, але може бути runtime помилка

// Кращі альтернативи any
let value: unknown = getData(); // Безпечніше ніж any
let result: string | number = getValue(); // Union type замість any

Коли використовувати: Тільки при міграції з JavaScript або роботі з динамічним контентом. Намагайтеся уникати.

Unknown

Безпечна альтернатива any:

let userInput: unknown;
let userName: string;

userInput = 5;
userInput = "Max";

// userName = userInput; // Помилка!

// Потрібна перевірка типу
if (typeof userInput === "string") {
    userName = userInput; // OK
}

Void

Відсутність значення (зазвичай для функцій):

function logMessage(message: string): void {
    console.log(message);
    // немає return або return без значення
}

function processData(data: any[]): void {
    data.forEach(item => console.log(item));
}

// Змінні типу void (рідко використовується)
let unusable: void = undefined;

Null та Undefined

Представляють відсутність значення:

let u: undefined = undefined;
let n: null = null;

// З strictNullChecks
let name: string | null = null; // Може бути рядком або null
let age: number | undefined; // Може бути числом або undefined

// Перевірка на null/undefined
function getStringLength(str: string | null): number {
    if (str !== null) {
        return str.length;
    }
    return 0;
}

// Optional chaining
interface User {
    name?: string;
    address?: {
        street?: string;
    };
}

function getUserStreet(user: User): string | undefined {
    return user.address?.street;
}

Never

Тип для значень, які ніколи не виникають:

// Функція, яка завжди кидає помилку
function error(message: string): never {
    throw new Error(message);
}

// Функція з нескінченним циклом
function infiniteLoop(): never {
    while (true) {
        // нескінченний цикл
    }
}

// Exhaustive checking
type Shape = "circle" | "square" | "triangle";

function getArea(shape: Shape): number {
    switch (shape) {
        case "circle":
            return Math.PI;
        case "square":
            return 4;
        case "triangle":
            return 3;
        default:
            const exhaustiveCheck: never = shape;
            return exhaustiveCheck;
    }
}

Об'єктні типи

Object

Загальний тип для об'єктів:

// Базовий object тип
let obj: object = { x: 0, y: 0 };

// Краще використовувати специфічні типи
interface Point {
    x: number;
    y: number;
}

let point: Point = { x: 10, y: 20 };

// Type aliases для об'єктів
type User = {
    id: number;
    name: string;
    email?: string; // Optional property
    readonly createdAt: Date; // Readonly property
};

// Index signatures
interface StringDictionary {
    [key: string]: string;
}

let dict: StringDictionary = {
    name: "Іван",
    city: "Київ"
};

Функції

Типізація функцій різними способами:

// Function type
let myAdd: (x: number, y: number) => number;
myAdd = function(x: number, y: number): number { 
    return x + y; 
};

// Arrow function
let multiply = (a: number, b: number): number => a * b;

// Optional parameters
function greet(name: string, title?: string): string {
    return title ? `${title} ${name}` : name;
}

// Default parameters
function createUser(name: string, role: string = "user"): User {
    return { name, role };
}

// Rest parameters
function sum(...numbers: number[]): number {
    return numbers.reduce((total, num) => total + num, 0);
}

// Function overloads
function formatDate(date: Date): string;
function formatDate(date: string): string;
function formatDate(date: Date | string): string {
    if (date instanceof Date) {
        return date.toISOString();
    }
    return new Date(date).toISOString();
}

Користувацькі типи

Enum

Іменовані константи:

// Numeric enum
enum Direction {
    Up = 1,
    Down,
    Left,
    Right,
}

// String enum (рекомендовано)
enum Color {
    Red = "red",
    Green = "green",
    Blue = "blue",
}

// Const enum (оптимізація)
const enum HttpStatus {
    Ok = 200,
    NotFound = 404,
    InternalServerError = 500,
}

// Практичне використання
function setTheme(color: Color): void {
    document.body.style.backgroundColor = color;
}

setTheme(Color.Blue);

Best practice: Використовуйте string enums для кращої читабельності та безпеки.

Tuple

Масиви з фіксованою кількістю та типами елементів:

// Базовий tuple
let coordinates: [number, number] = [10, 20];
let nameAge: [string, number] = ["Олена", 25];

// Labeled tuples
let point: [x: number, y: number] = [1, 2];

// Optional elements
let optionalTuple: [string, number?] = ["test"];

// Rest elements
let restTuple: [string, ...number[]] = ["prefix", 1, 2, 3];

// Практичні приклади
function useState<T>(initial: T): [T, (newValue: T) => void] {
    let value = initial;
    const setValue = (newValue: T) => {
        value = newValue;
    };
    return [value, setValue];
}

// Деструктуризація
let [name, userAge] = nameAge;
let [x, y] = coordinates;

Union типи

Об'єднання декількох типів:

// Базові union типи
let id: number | string;
id = 101; // OK
id = "202"; // OK

// Union з literal types
type Status = "loading" | "success" | "error";
type Response = string | number | boolean;

// Discriminated unions
interface LoadingState {
    status: "loading";
}

interface SuccessState {
    status: "success";
    data: string;
}

interface ErrorState {
    status: "error";
    error: string;
}

type AppState = LoadingState | SuccessState | ErrorState;

// Type guards
function handleState(state: AppState): void {
    switch (state.status) {
        case "loading":
            console.log("Завантаження...");
            break;
        case "success":
            console.log("Дані:", state.data);
            break;
        case "error":
            console.log("Помилка:", state.error);
            break;
    }
}

// User-defined type guards
function isString(value: unknown): value is string {
    return typeof value === "string";
}

function processValue(value: string | number): void {
    if (isString(value)) {
        console.log(value.toUpperCase()); // TypeScript знає, що це string
    } else {
        console.log(value.toFixed(2)); // TypeScript знає, що це number
    }
}

Intersection типи

Об'єднання властивостей декількох типів:

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

interface Employee {
    company: string;
    position: string;
}

// Intersection type
type PersonEmployee = Person & Employee;

let worker: PersonEmployee = {
    name: "Іван",
    age: 30,
    company: "TechCorp",
    position: "Developer"
};

// Mixins pattern
interface Timestamped {
    timestamp: Date;
}

interface Tagged {
    tags: string[];
}

type BlogPost = {
    title: string;
    content: string;
} & Timestamped & Tagged;

Type Aliases vs Interfaces

// Type alias
type Point = {
    x: number;
    y: number;
};

// Interface
interface PointInterface {
    x: number;
    y: number;
}

// Розширення
type ExtendedPoint = Point & { z: number };

interface ExtendedPointInterface extends PointInterface {
    z: number;
}

// Declaration merging (тільки для interfaces)
interface Window {
    customProperty: string;
}

Коли використовувати:

  • Interface: Для описання форми об'єктів, особливо коли потрібне розширення
  • Type alias: Для union types, primitives, computed types

Практичні поради

1. Strict режим

// В tsconfig.json
{
    "compilerOptions": {
        "strict": true,
        "noImplicitAny": true,
        "strictNullChecks": true
    }
}

2. Utility types

// Partial - робить всі властивості опціональними
interface User {
    id: number;
    name: string;
    email: string;
}

type PartialUser = Partial<User>; // всі поля опціональні

// Pick - вибирає певні властивості
type UserPreview = Pick<User, "id" | "name">;

// Omit - виключає певні властивості
type CreateUser = Omit<User, "id">;

// Record - створює тип з ключами та значеннями
type UserRoles = Record<string, boolean>;

3. Conditional types

type IsArray<T> = T extends any[] ? true : false;

type Test1 = IsArray<string[]>; // true
type Test2 = IsArray<string>; // false

Висновок

Розуміння типів TypeScript дозволяє:

  • ✅ Виловлювати помилки на етапі компіляції
  • ✅ Покращити автодоповнення в IDE
  • ✅ Зробити код більш читабельним та підтримуваним
  • ✅ Забезпечити кращу документацію коду

Золоті правила:

  1. Використовуйте strict режим
  2. Уникайте any, віддавайте перевагу unknown
  3. Використовуйте union types замість any
  4. Застосовуйте type guards для звуження типів
  5. Використовуйте literal types для точності

Почніть з простих типів та поступово переходьте до більш складних конструкцій. TypeScript стане вашим надійним помічником у створенні якісного коду!