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

Введение

Если ваш разработчик React наверняка уже читал это сообщение: «не удается получить доступ к свойству «имя», пользователь не определен» или что-то в этом роде.
С Typescript вы можете избежать этой ситуации во многих случаях. Но когда вы используете данные приложения, например, из REST API, сложнее предотвратить это исключение с помощью Typescript, потому что он не может иметь доступ ко всем структурам данных или изменениям моделей на стороне сервера.

Проблема

Например, вы получаете этот JSON с сервера, когда вы вызываете конечную точку для получения профиля пользователя:

{
    email: "[email protected]",
    name: "Will",
    avatar: { url: "https;//website.avatar.jpg" }
}

Затем вы создаете этот тип для использования входящих данных с минимальной ошибкой с помощью Typescript.

export interface UserProfile {
    email:  string;
    name:   string;
    avatar: Avatar;
}
export interface Avatar {
    url: string;
}

Но в день из-за ошибки сервера ваше приложение получает пустой объект {} вместо предварительного просмотра объекта JSON. Затем, если в вашем приложении вы напишите что-то вроде этого:

const [avatarUrl, setAvatarUrl] = useState('https://i.default.jpg');
...
const profile:UserProfile = await responseServer.json()
setAvatarUrl(profile.avatar.url);
...

Последняя строка кода ниже вызовет исключение внутри вашего приложения.

Решение

Мы собираемся использовать пример предварительного просмотра, чтобы объяснить стратегию решения этого типа проблемы.

1. Сделайте все ваши свойства необязательными

Сделайте все свойства ваших типов или интерфейсов необязательными, даже если вы думаете, что они никогда не будут таковыми. Цель здесь состоит в том, чтобы предотвратить непредвиденные случаи, когда свойство больше не присутствует в нашей структуре данных. Теперь ваш интерфейс должен выглядеть так

export interface UserProfile {
    email?:  string;
    name?:   string;
    avatar?: Avatar;
}
export interface Avatar {
    url?: string;
}

2. Используйте дополнительную цепочку

Когда вы делаете все свои свойства необязательными и пытаетесь получить одно из них следующим образом:

profile.avatar.url

Typescript заметит, что: аватар может быть нулевым или неопределенным, а затем создаст исключение. Затем используйте другой синтаксис, чтобы получить свойство url:

profile?.avatar?.url

Таким образом, если профиль или аватар имеет значение null, процесс не создаст исключение.

3. Укажите альтернативное значение в нулевом или неопределенном случае.

Чтобы улучшить UX вашего приложения, вам необходимо указать URL-адрес по умолчанию в случае, если URL-адрес, полученный из данных ответа сервера, равен нулю или не определен.

setAvatarUrl(profile?.avatar?.url || 'https://i.default.jpg');

Затем, когда profile?.avatar?.url не равно null или undefined, он передается как параметр, иначе 'https://i.default.jpg' используется как альтернатива .

Заключение

Эту стратегию можно использовать во многих сценариях, чтобы, во-первых, избежать сбоя вашего приложения, а во-вторых, предоставить данные, понятные пользователю. Но это не замена ErrorBoundary. Вы можете использовать это в большинстве случаев и не только для аватара. В последнем примере вместо использования {user.amount.value} используйте {user?.amount?.value || «Н/Д»