
Деструктурировать из возможно неопределенного свойства объекта
Проблема
Функция updateUserProfile позволяет мне получить user, сделав запрос к базе данных с предоставленным user_id, затем использовать другой запрос к базе данных, чтобы гарантировать, что предоставленный email не принадлежит другому пользователю, и, наконец, обновить пользователя в базу данных, отправив запрос с предоставленными name и email.
Проблема заключалась в том, что при проверке наличия пользователя с предоставленным email в базе данных результатом мог быть Userобъект или undefined, в зависимости от того, нашли ли мы пользователя или нет.
Объект User содержит множество свойств (id, name, email, avatar, password. >, created_at, updated_at), но мне нужно было только свойство id сравнить с предоставленным user_id, чтобы гарантировать, что письмо не принадлежит ни одному пользователю.
Я не смог использовать деструктурирование, чтобы распаковать только id из результата или переименовать его в findEmailOwner, потому что результатом может быть User объект или undefined, поэтому я получил следующее сообщение об ошибке TypeScript: «Свойство 'id' не существует для типа 'Пользователь | неопределенный'".
TLDR: мне нужно получить id путем деструктуризации значения, которое может быть object или undefined.
function updateUserProfile ({ user_id, name, email }) {
const user = await usersRepository.findById(user_id);
if (!user) {
throw new AppError(`The user was not found.`, 401);
}
const { id: findEmailOwner } = await usersRepository.findByEmail(email);
// error message: “Property ‘id’ does not exist on type ‘User | undefined’.
if (typeof findEmailOwner !== ‘undefined’ && findEmailOwner !== user_id) {
throw new AppError(`This email cannot be used.`, 401);
}
user.name = name;
user.email = email;
return usersRepository.save(user);
}
Отвечать
- Мы можем использовать краткую оценку для предоставления по умолчанию, если
userявляется ложным значением (undefined,null,0,-0,0n,””илиNaN).
ПРИМЕЧАНИЕ 1. Я могу использовать этот подход в своем приложении, поскольку id свойство, которое я хочу получить с помощью деструктуризации, не может быть присвоено какому-либо ложному значению в моей базе данных.
ПРИМЕЧАНИЕ 2. НО, если бы я получал свойство avatar, которое может быть назначено null в базе данных, этот подход не сработал бы.
// Case 1 — id (cannot contain falsy values)
// user does not exist
const user = undefined;
const { id } = user || {};
console.log(id); // undefined (what we expect)
// user exists
const user = {
id: ‘aaaa-aaaa-aaaa-aaaa’,
};
const { id } = user || {};
console.log(id); // ‘aaaa-aaaa-aaaa-aaaa’ (what we expect)
// Result: SUCCESS
// — — — — — — — — — — — — — — — — — — — — -
// Case 2 — avatar (can contain null a falsy values)
const user = undefined;
const { avatar } = user || {};
console.log(avatar); // undefined (what we expect)
const user = {
avatar: ‘photo.jpg’,
};
const { avatar } = user || {};
console.log(avatar); // ‘photo.jpg’ (what we expect)
const user = {
avatar: null,
};
const { avatar } = user || {};
console.log(avatar); // undefined (not good, we needed this to be null)
// Result: FAILURE
- Другой подход – распространить
userна объект перед его деструктурированием, поскольку значенияnullиundefinedигнорируются.
ПРИМЕЧАНИЕ 1. Я бы использовал этот подход, если бы извлекал avatar свойство, которое может быть присвоено ложному значению. (null) в базе данных, так как первый подход не сработал.
ПРИМЕЧАНИЕ 2. Этот подход менее идиоматичен, поэтому я бы не стал использовать его в тех случаях, когда работает первый подход.
ПРИМЕЧАНИЕ 3. Этот подход также работает для id.
//Case — avatar (can contain null a falsy values)
const user = undefined;
const { avatar } = { …user };
console.log(avatar); //undefined (what we expect)
const user = {
avatar: ‘picture.jpg’,
};
const { avatar } = { …user };
console.log(avatar); // ‘picture.jpg’ (what we expect)
const user = {
avatar: null,
};
const { avatar } = { …user };
console.log(avatar); // null (what we expect)
// Result: SUCCESS
Применение метода оценки короткого замыкания к нашему коду:
function updateUserProfile ({ user_id, name, email }) {
const user = await usersRepository.findById(user_id);
if (!user) {
throw new AppError(`The user was not found.`, 401);
}
const { id: findEmailOwner } = (await usersRepository.findByEmail(email)) || {}; // 1st approach
if (typeof findEmailOwner !== ‘undefined’ && findEmailOwner !== user_id) {
throw new AppError(`This email cannot be used.`, 401);
}
user.name = name;
user.email = email;
return usersRepository.save(user);
}
TLDR
- Получение свойства (которое не может быть ложным) с деструктуризацией значения, которое может быть object или undefined — используйте оценку короткого замыкания.< br /> - Получение свойства (которое может быть ложным) с деструктурированием из значения, которое может быть object или undefined — используйте оператор распространения на значение, которое может быть объектом или неопределенным.
Дополнительные ссылки
- [JS/ES6: деструктуризация неопределенного при переполнении стека](https://stackoverflow.com/questions/48433008/js-es6-destructuring-of-undefined)
Поддерживать связь
Свяжитесь со мной через мои социальные сети. Давайте поговорим о DDD, TDD, хороших практиках и новом фильме Чудо-женщина 1984, будь то на LinkedIn или GitHub.
Расскажите, что вы сегодня узнали.