Урок 02

Опциональные и readonly свойства

Опциональные свойства

Знак ? делает свойство необязательным:

type User = {
    name: string;
    email?: string;
    phone?: string;
};

const user1: User = { name: 'Алиса' };
const user2: User = { name: 'Боб', email: 'bob@example.com' };

При чтении опциональное свойство имеет тип T | undefined:

user.email;          // string | undefined
user.email?.length;  // безопасно
user.email!.length;  // небезопасно

Опциональные параметры функций

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

Опциональность в интерфейсах

interface Config {
    url: string;
    timeout?: number;
    retries?: number;
}

Значения по умолчанию

Часто опциональность комбинируется со значением по умолчанию:

function fetch(url: string, timeout: number = 5000) {}

Параметр с дефолтом автоматически опционален.

Readonly

readonly запрещает изменение свойства после создания:

type User = {
    readonly id: number;
    name: string;
};

const user: User = { id: 1, name: 'Алиса' };
user.name = 'Боб'; // ок
user.id = 2;       // ошибка

Readonly в массивах

const numbers: readonly number[] = [1, 2, 3];
numbers.push(4); // ошибка
numbers[0] = 10; // ошибка

Или через ReadonlyArray:

const numbers: ReadonlyArray<number> = [1, 2, 3];

ReadonlyArray vs readonly T[]

Оба варианта эквивалентны:

const a: readonly string[] = ['a'];
const b: ReadonlyArray<string> = ['a'];

Readonly в интерфейсах

interface Point {
    readonly x: number;
    readonly y: number;
}

Readonly не глубокий

readonly защищает только верхний уровень:

type User = {
    readonly address: {
        city: string;
    };
};

const user: User = { address: { city: 'Москва' } };
user.address = { city: 'Питер' }; // ошибка
user.address.city = 'Питер';     // ок

Чтобы защитить вложенное — readonly внутри:

type User = {
    readonly address: {
        readonly city: string;
    };
};

Утилита Readonly

Преобразует все свойства в readonly:

type User = {
    name: string;
    age: number;
};

type ReadonlyUser = Readonly<User>;
// { readonly name: string; readonly age: number }

Const assertion

Для объектов и массивов:

const config = {
    host: 'localhost',
    port: 3000,
} as const;

config.host = 'example.com'; // ошибка

as const делает всё readonly и выводит литеральные типы.

Итоги

  • ? — опциональное свойство
  • Чтение опционального — T | undefined
  • readonly — только для чтения
  • readonly T[] — неизменяемый массив
  • Readonly<T> — все свойства readonly
  • as const — литеральные типы и readonly