# Типизация

## По умочанию используем генерацию union-типов из констант, где не нужна непрозрачность значений

В разработке ui-компонентов для списков допустимых значений используем по умолчанию union-типы, сгенерированные из одноимённых констант, если нет особых причин использовать enums:
```typescript jsx
export const ButtonSizes = ['l', 'm', 's', 'xs'] as const;
export type ButtonSizes = typeof ButtonSizes[number];

() => <Button size={'s'}>
console.log(ButtonSizes);
// Output: ['l', 'm', 's', 'xs']
```

Преимущества union-типов:
* Лего и лаконично декларировать, компановать.
* В качестве значения свойств данного типа можно указывать исходные строки. Это удобно для таких свойств как размер, цветовая тема, выравнивание, которые сквозные для нескольких компонентов. Аналогичным компонентам в составе другого компонента можно передавать один размер `'s'`, тему `'gray'` или выравнивание `'right'` без ненадёжного приведения типов или дополнительных проверок.
* Меньше лишнего кода при компиляции, чем у enum, меньше бандлы.
* Генерация из одноимённых констант делает допустимые значения доступными в качестве массива в рантайме под тем же имененем, в отличии от обычного union:
```typescript jsx
export type ButtonSizes = 'l' | 'm' | 's' | 'xs';

console.log(ButtonSizes);
// Error: 'ButtonSizes' only refers to a type, but is being used as a value here.
```

Это позволяет автоматизировать обновление комбинаторных скриншотных тестов, исключив человеческий фактор. Если раньше мы часто забывали обновлять в сторибуке хардкод вроде
```typescript jsx
['l', 'm', 's'].map(size => <Button size={size}>)
// новые размер 'xs' не проверяется
```
и поэтому не могли проверить, что новый размер кнопки корректно работает в комбинации сдругими свойствами или в составе других компонентов.

Теперь в storybook напрямую импортируются актуальные массивы значений сразу после их изменения и обновляются скриншоты:
```typescript jsx
import { ButtonSizes } from '../types';

ButtonSizes.map(size => <Button size={size}>)
```
Разработчик на автоматически обновлённых скриншотах в PR видит все актуальные комбинации свойств компонента, втом числе в составе других компонентов, которые импортируют тот же актуальный массив значений для комбинаторных скриншотов.

## Используем enum в случаях, когда не хотим допускать сырые строки в качестве значений

Валидный кейс использования enum — скрыть внутреннюю реализацию, например, в случае работы с данными бэкэнда:
```typescript jsx
export enum OrderStatus {
    Create = 'some-backend-status-name',
    InProcess = 'might-change-later',
    Complete = 'dont-want-to-leak-into-frontend',
};

Object.values(OrderStatus).map(status => <Status type={status} />);

() => <Status type={'some-backend-status-name'} />
// type error: в данном слуаче ошибка на помогает не хардкодить наименования с бэкэнда на фронте
```





