Лише Гуру TypeScript побачать помилку в цьому рядку коду!

Уважно подивіться на наведену нижче TypeScript функцію з одного рядку коду. В ній є проблема пов’язана з типами. Чи можете ви її побачити?

Пропоную просто зараз зупинитись та запропонувати вашу версію в коментарях.


Перша підказка

// Завантажуємо массив уявних записів із бази даних
const posts = await loadPostsFromDataBase();

// Хочемо отримати кількість доступних записів
// Але отримуємо TS2345 помилку від TypeScript
const postsCount = getArraylength(posts);

Наведений вище код призводить до помилки невідповідності типу аргументу posts до типу параметра arr. За яких умов це можливо, якщо loadPostsFromDataBase працює абсолютно коректно, а проблема саме в getArraylength?

Здогадались?


Остання підказка

В якості останньої підказки покажу тіло функції loadPostsFromDataBase:

function loadPostsFromDataBase(): readonly Post[] {
  return fetch('/api/posts')
    .then(r => r.json())
    .then(posts => Object.freeze(posts))
}

Відповідь

За замовчуванням всі типи в TS є мутабельними. Тобто, оголошуючи функцію з параметрами як тут:

function getArraylength(arr: unknown[]): number {
  return arr.length
}

Ви кажете “Ця функція потребує мутабельний масив та повертає число”.

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

Тому, ви отримаєте помилку, якщо спробуєте передати аргументом readonly масив, не зважаючи на те, що насправді з точки зору JavaScript код абсолютно вірний.

const posts = await loadPostsFromDataBase(); // readonly Posts[]

const postsCount = getArraylength(posts); // ❌ The type 'readonly Post[]' is 'readonly' and cannot be assigned to the mutable type 'unknown[]'

TypeScript Playground

Рішення

Ото ж, у функції не правильно вказано тип для параметра. Як же тоді цю проблему вирішити?

Все просто. Якщо ваша функція, не змінює вхідні параметри, а це хороший патерн проєктування, тоді типи ваших параметрів повинні бути readonly:

function getArraylength(arr: readonly unknown[]): number {
  return arr.length
}

Така сигнатура каже, “Мені потрібен масив, який я буду лише читати”. І в цьому випадку, TypeScript дозволить передавати параметром як звичайні змінні, так і readonly:

const posts = []
const readOnlyPosts: readonly [] = []

getArraylength(posts) // ✅
getArraylength(readOnlyPosts) // ✅

TypeScript playground

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Олександр Козак
Олександр Козак@kozack

6.6KПрочитань
1Автори
68Читачі
Підтримати
На Друкарні з 14 квітня

Більше від автора

  • Детальний огляд семантики HTML теґів. Різниця між <section> та <article>

    Огляд семантики HTML: розрізнення між <section> та <article>, значення правильного використання тегів та їх роль у структурі вебсторінки. Дослідження важливості семантики для SEO та доступності, а також рекомендації щодо використання HTML-елементів та ролей

    Теми цього довгочиту:

    Html
  • Про доступність та UI на прикладі мого особистого сайту

    Знайомтесь це мій особистий сайт. Перший знімок те яким він був ДО другий - ПІСЛЯ сьогоднішнього патчу. І в цій короткій статті я хочу зробити маленьке ревью та розказати на прикладах ЧОМУ я реалізував деякі дивні речі.

    Теми цього довгочиту:

    Доступність
  • Як зробити нескінченну прокрутку на сайті. Або 10 недоліків та одна перевага Infinity Scroll

    В цій статті я хочу описати 10 поширених проблем, пов’язаних з нескінченною прокруткою, які розробнику доведеться вирішувати при реалізації Infinity Scroll. Та про єдину причину, чому попри всі недоліки нескінченну прокрутку активно використовують.

    Теми цього довгочиту:

    Ui-ux

Вам також сподобається

Коментарі (3)

оце було цікаво, ніколи таке не траплялося, але прикольно знати на майбутнє)

Вам також сподобається