Представим, что мы пишем свою реализацию “хранилища” данных, которое должно возвращать примерно такое состояние:
interface State<T = unknown> {
status: 'loading' | 'error' | 'success',
error: Error | undefined,
data: T | undefined,
}
На первый взгляд может показаться что всё ок, однако это не совсем так. К примеру, проверка status ничего не скажет нам о состоянии других полей:
if (state.status === 'success') {
console.log(state.data.toFixed());
// Получаем ошибку
// 'state.data' is possibly 'undefined'.
}
Решаем проблему через union тип, добавляя три (по количеству состояний) отдельных интерфейса в каждом из которых error и data напрямую зависят от значения status:
interface LoadingState {
status: 'loading';
error: undefined;
data: undefined;
}
interface ErrorState {
status: 'error';
error: Error;
data: undefined;
}
interface SuccessState<T = unknown> {
status: 'success';
error: undefined;
data: T;
}
type State<T = unknown> =
| LoadingState
| ErrorState
| SuccessState<T>;
Проверяем наш код, и видим что всё работает без ошибок 🎉:
if (state.status === 'success') {
console.log(state.data.toFixed());
}
if (state.status === 'error') {
console.log(state.error.message);
}
Кстати, тоже самое можно провернуть и с типизацией props для React компонента, который должен принимать разный набор параметров в зависимости от значения одного общего.
type GridProps = SharedProps & (GridTypeProps | FlexTypeProps);
Больше информации в Telegram канале https://t.me/around_dev