Кейс на автодополнение TS

Представьте, у вас есть функция, который работает со строкой и массивом. Для нагядности код будет ниже `function randomItem(arrayLike){ return arrayLike[Math.floor(Math.random() * arrayLike.length)] }

В данной фукции есть "2 подвоха"

  • randomItem будет работать с любым "объектом" (или строкой) у кого есть взятие по индексу и у кого есть поле "length"
  • Типизировать unknown[] | string не вариант, т.к. есть в проекте другие структуры, у кого также есть обращение по индексу и обращение по свойству length.

Да, можно прописать в тип все возможные типы и получить что-то такое

`function randomItem(arrayLike: unknown[] | string | MyStructure1 | MyStructure2){ // implementation }

Можно даже вынести в Generic `function randomItem (arrayLike: T): T[number] { // implementation }

При появлении новой структуры, вы 100% забудете дописать эту структуру в сигнатуру, а еще можно заметить в примере выше, что мы обращаемся к T[number]. Так какое же решение?

Массив, строка и прочие "array-like" объекты можно обобщить под один тип. Давайте посмотрим на примере таких типов `type IsArrayLike = T extends { length: number } ? true : false

type TestArr = IsArrayLike // true type TestReadonlyArr = IsArrayLike // true type TestStr = IsArrayLike // !!!! true!!!!!!

type IsArrayIndexable = T extends { [key: number]: unknown }

type TestArr = IsArrayIndexable // true type TestReadonlyArr = IsArrayIndexable // true type TestStr = IsArrayIndexable // !!!! true!!!!!!

Так, и что нам это дает? И поскольку мы обращаемся по числовому индексу, то следующий код и будет решением нашей задачи `type ArrLike = { [key: number]: Values length: number }

function randomItem(arrLike: T): T[number] { // implementation }

И вот примеры использования

`randomItem('myString') // randomItem => string randomItem([1,2,3]) // randomItem<[1,2,3]> => 1 | 2 | 3 randomItem({length: 2, 1: 'qwe', 2: 'asd'} ) // randomItem() => unknown

Бонус контент - фикс для объекта (без infer тут никак, извините) `type ArrLike = { [key: number]: Values length: number } function randomItem = ( arrayOfItems: T, ): T extends ArrLike ? Val : unknown => { // implementation }

#ts #js #tip_of_the_day #javascript #typescript @haradkou_sdet```````