dev.easy
132 subscribers
11 links
заметки full stack девелопера - находки, фишечки и боль современной web-разработки


notion blog: https://bit.ly/deveasy

github: https://github.com/z4o4z
Download Telegram
🎹 Массивы и Таплы

В TS/JS массивы можно разделить на 2 типа, обычные массивы и таплы (tuple). На данный момент для js-движков между ними нет разницы и обрабатываются они как массивы. На практике таплы чаще всего используются в ситуациях, когда нужно вернуть несколько(2-3) значений из функции, если нужно больше, то лучше использовать объект.
Например в React'е, useState возвращает тапл со значением и сеттером.
Почему тапл лучше объекта для нескольких значений? При деструкторизации тапл проще использовать чем объект, а так же с ним меньше мест в которых можно допустить ошибку, достаточно знать лишь порядок данных. С объектом же нужно точно знать какие есть ключи и каких у них данные, а при деструкторизации нужно тупо больше кода для таких широко-используемых функций как useState :


// tuple
const [state1, setState1] = React.useState(0);
const [state2, setState2] = React.useState(false);

// vs

// object
const { val: state1, set: setState1 } = React.useState(0);
const { val: state2, set: setState2 } = React.useState(false);


Согласитесь вариант с таплом намного удобнее и читабельнее объекта. Но повторюсь, тапл хорош только для нескольких значений, желательно до 3. Иначе будет каша с кучей данных, разных типов, без названий. Держать такое в голове, также как и сапортать, оч сложно.

Вернемся к TS, для определения тапла, типы элементов должны быть между [] скобок, таким образом мы явно говорим TSу, что элемент под таким-то индексом имеет такой-то тип. В массивах же тип задается всему массиву:


// tupples
type SimpleTuple = [string, boolean];
type NamedTuple = [isOpened: boolean, toggleOpened: VoidFunction];
type NamedLongTuple = [a: string, b: number, c: VoidFunction, d: boolean | undefined, e: unknown]; // BAD, better to use object
type TailTuple = [...string[], number];
type DestructTuple = [head: number, ...body: string[], tail: number];

// arrays
type SimpleArray = string[];
type UnionArray = Array<string | boolean>; // (string | boolean)[]


Как вы заметили, таплы в TS могут иметь неопределённую длину, а также типы элементов можно задавать с конца. Кстати, VoidFunction это алиас на () => void который идет по дефолту в dom неймспейсе, те кто пишет под брузер можете юзать :). Теперь давайте разберем на примере разницу между массивом и таплом:


const tuple: SimpleTuple = ['NAME', false];
const array: UnionArray = ['NAME', false];
const untyped = ['NAME', false];

// works fine, since TS knows that first item is a string!
tuple[0].toLowerCase();

// error: Property 'toLowerCase' does not exist on type 'string | boolean'
// since first element can be string or boolean
array[0].toLowerCase();

// same error as above
untyped[0].toLowerCase();


array[0].toLowerCase(); и untyped[0].toLowerCase(); выдадут ошибки, потому что для array мы явно указали тип всех элементов массива как string | boolean , а untyped так-же получил тип Array<string | boolean> т.к. всем массивам присвоенным в переменную без явно указанного типа TS дает тип всех его элементов, т.е. в нашем случае будет юнион string | boolean . Но есть синтаксис как подсказать TS'у что untyped это тапл, а не массив:


const untyped = ['NAME', false] as const;

untyped[0].toLowerCase(); // works fine


Продолжение в первом коменте...
Читать в ноушен: https://bit.ly/3kxH8aQ

#typescript #js
💯1🤓1