#typescript
#typescript
Вопрос:
Цель
Цель состоит в том, чтобы создать объект при условном добавлении свойств. Применяются следующие правила:
- не допускается, чтобы в конечном итоге для необязательного свойства было установлено значение undefined .
- это должно быть сделано встроенным (например, без циклов / .reduce и т. Д. Для создания объекта)
Два сценария
Рассмотрим следующий код:
interface User {
readonly firstName: string
readonly lastName: string
}
interface ParitalUser {
readonly firstName?: string
readonly lastName?: string
}
const updateLastName = false
// SCENARIO 1
// create a user and conditionally add a name property
const partialUserA: ParitalUser = {
...(updateLastName ? { lastName: 'Doe' } : {}),
}
// i want the following assertion pass (so 'userA' should not have a property 'name' if addName is false)
console.assert(!('lastName' in partialUserA))
// but this is not type safe:
const partialUserB: ParitalUser = {
...(Math.random() < 0.5 ? { lastName: 'Doe' } : {}),
...(Math.random() < 0.5 ? { age: 21 } : {}), // should be an error, but isn't!
}
// SCENARIO 2
// i know I can do this
const partialUserC: ParitalUser = {
lastName: updateLastName ? 'Doe' : undefined,
}
// this is type safe:
const partialUserB: ParitalUser = {
lastName: updateLastName ? 'Doe' : undefined,
age: Math.random() < 0.5 ? 21 : undefined, // is an error (as it should be)
}
// but the this assertion doesn't pass anymore
console.assert(!('lastName' in partialUserC))
(игровая площадка, с которой можно поиграть, находится здесь)
Проблема
SCENARIO 1
приводит к объекту без свойстваlastName
, но он не является типобезопаснымSCENARIO 2
является типобезопасным, но приводит к объекту с неопределенным свойствомlastName
(см. Правило 1)
Но почему?
Рассмотрим следующий код:
const userToUpdate: User = {
firstName: 'Frank',
lastName: 'Smith',
}
const userA: User = {
...userToUpdate,
...partialUserA,
}
// becomes { firstName: 'Frank', lastName: 'Smith' }
const userC: User = {
...userToUpdate,
...partialUserC,
}
// becomes { firstName: 'Frank', lastName: undefined }
(игровая площадка, с которой можно поиграть, находится здесь)
Предполагаемое использование всего этого — создавать частичные объекты, которые представляют свойства, которые необходимо обновить.
userC
, который был «обновлен» с использованием объекта, содержащего undefined
свойство, неправильно перезаписывает это свойство. userA
создается правильно с использованием partialUserA
, но это не было (см. Выше) типобезопасной операцией.