Кейс на автодополнение 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```````