string[] і Array<string> - одне й те саме, два записи одного типу. Короткий запис зазвичай читається простіше; узагальнений зручніший для складних типів елементів:
const tags: string[] = ['php', 'vue'];
const handlers: Array<() => void> = []; // замість (() => void)[]
Readonly-масиви забороняють змінювати масив через це посилання:
function sum(values: readonly number[]): number {
values.push(1); // помилка: push немає в readonly number[]
values[0] = 5; // помилка
return values.reduce((a, b) => a + b, 0); // читання - можна
}
readonly number[] і ReadonlyArray<number> - знову два записи одного типу. Методи, що змінюють масив (push, pop, splice, sort, reverse), у ньому відсутні; немутуючі (map, filter, toSorted) - доступні.
Навіщо:
- контракт функції: параметр
readonly T[]повідомляє, що функція масив не змінить. Викликач може спокійно передати свій стан; - ширша сумісність: у
readonly number[]можна передати і звичайний масив, і readonly. Функція з параметромnumber[]не прийме readonly-масив. Тому для параметрів, які лише читаються,readonly- кращий вибір; - стан у React/Vue/Redux: заборона випадкової мутації на рівні типів.
as const робить масив літералів readonly-кортежем:
const sizes = ['sm', 'md', 'lg'] as const; // readonly ['sm', 'md', 'lg']
type Size = (typeof sizes)[number]; // 'sm' | 'md' | 'lg'
Обмеження:
- лише на рівні типів: під час виконання це звичайний масив. Хтось із посиланням
number[]чи черезasможе його змінити. Для справжньої незмінності -Object.freeze; - поверхнево:
readonly User[]забороняє змінювати масив, але не об'єкти в ньому -users[0].name = 'x'пройде. Для глибокої незмінності -ReadonlyArray<Readonly<User>>або власний типDeepReadonly; - присвоєння readonly-масиву в змінну типу
T[]- помилка; інколи це змушує додаватиreadonlyу сигнатури по всьому ланцюжку викликів (і це правильно).