Лише Гуру 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

4.6KПрочитань
1Автори
59Читачі
На Друкарні з 14 квітня

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

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

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

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

    Ui-ux
  • Чому ви повинні забути про rgb() та hex кольори при роботі з вебсайтами

    Формат задання кольорів функцією rgb() було представлено ще у 1996 році. Очевидно, що CSS далеко розвинувся з тих часів. Попри це, чомусь, багато веброзробників та вебдизайнерів вперто продовжують використовувати цей застарілий, обмежений та нелюдський формат кольору по цей день.

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

    Css
  • Чому автоматичні імпорти будь-де це жахлива ідея 💩

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

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

    Javascript

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

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

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

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