#reactjs #typescript
#reactjs #typescript
Вопрос:
Я часто сталкиваюсь с ситуацией, когда я сохраняю объект в состоянии реакции, например, пользователя:
...
user: undefined,
setUser: (user) => set((state) => ({ user: { ...user, ...state.user } as User })),
Я определяю тип TypeScript как
export type User = {
verified: boolean;
firstName: string;
lastName: string;
userType: 'user' | 'admin';
};
Итак, на данный момент TypeScript будет жаловаться на то, что user
, который я создаю как User
тип, является undefined
, хотя этого не может быть. ОТЛИЧНО! Поэтому я добавляю | undefined
в конце User
определения типа. Итак, это позаботится об этом конкретном файле, но затем я начинаю получать миллион и одно другое предупреждение повсюду, потому что, например, я вызываю user.firstName
, но теперь, когда пользователь может быть неопределенным, я действительно должен вызвать user?.Имя пользователя.
Добавление условий, таких как if(user)
, похоже, не удовлетворяет TS. В итоге я трачу три часа на исправление ошибок для TS, только чтобы узнать, что мой код теперь ломается из-за этого недавнего изменения.
Это очень похоже на попытку подавить пожары, которые я сам запустил, когда использовал TypeScript. Разочарование.
Может ли кто-нибудь, кто хорошо знает TS, пожалуйста, предложить некоторые рекомендации? Как бы вы подошли к этому? Есть ли способ обрабатывать такие «неопределенные» случаи?
Ответ №1:
Предполагая, что вы определили пользователя как:
const user: User|undefined = ...;
Если вы хотите получить доступ к свойству пользователя, используйте этот синтаксис:
user!.firstName
Это говорит typescript, что вы знаете, что делаете, и это user
никогда не является неопределенным или нулевым. Он также сообщает typescript, что свойства, к которым обращаются таким образом, не должны предполагаться, что они могут быть null
или undefined
, и я предполагаю, что именно поэтому вы теперь получали больше ошибок.
Внимание!
const user: User|undefined = ...;
избыточный ввод. Вы можете просто вернуться к использованию
const user: User = ...;
но вместо того, чтобы использовать ?.
оператор для доступа к свойствам, продолжайте использовать !.
.
Извините, если вы впервые используете typescript. Обычно все не так плохо.
Комментарии:
1. Полезный совет по поводу восклицательного знака. Забыл об этом.
Ответ №2:
Рассмотрите возможность разделения ваших компонентов на:
- Компоненты, у которых ДОЛЖЕН быть пользователь
- Компоненты, у которых МОЖЕТ быть пользователь
Из компонента, у которого может быть пользователь, отобразите компонент, у которого он должен быть.
class UserComponent extends React.Component<{ user: User }> {
render() {
// Note: since user must be defined for this component, we are able to access properties without the ? or ! syntax
return (
<div>{this.props.user.firstName}</div>
)
}
}
// Note: this.state.user is optional, and therefore is initialized as undefined
class MayHaveUserComponent extends React.Component<{}, { user?: User }> {
render() {
if (this.state.user) {
return <UserComponent user={this.state.user} />
}
return (
<div>No user yet!</div>
)
}
setUser(user: User) {
this.setState({ user: { ...user, ...this.state.user } })
}
}
Комментарии:
1. Интересная идея, но не сработает для моего потока приложений.
Ответ №3:
Вы не просто делаете typescript счастливым здесь. Если вы переходите user: undefined
к коду, который ожидает, что будет объект user, то это определенно вызовет ошибки во время выполнения при использовании undefined
like an object. Эти проверки необходимы, если это должно быть разрешено.
Обычно я справляюсь с этим в react, возвращая ранний рендеринг, если требуемое значение равно null
или undefined
. После этого возврата вы можете предположить, что пользователь существует как обычно.
class Component({ user: User | null | undefined }) {
if (!user) return <SomeLoadingIndicator /> // or: return null, or whatever
// from here on, `user` is known to be of type `User`, not null, and not undefined.
return <div>{user.lastName}</div>
}
Добавление условий, таких как
if(user)
, похоже, не удовлетворяет TS.
Это действительно так. Вам просто нужно быть в условной ветке, где была запущена проверка. Это означает, что вы должны быть в { }
инструкции if:
const user: User | null = Math.random() > 0.5 ? getUser() : null
if (user) {
// here user is of type: User
} else {
// here user is of type: null
}
// here user is of type: User | null
Или в коде, который мог выполняться только в том случае, если условие было правдивым.
const user: User | null = Math.random() > 0.5 ? getUser() : null
if (!user) {
// here user is of type: null
throw new Error("user is required!")
}
// here user is of type: User
Комментарии:
1. Вы правы в том, что TS соблюдает условие. Это была ошибка с моей стороны. Здесь есть хорошие моменты.