#reactjs #typescript #react-router
#reactjs #typescript #react-маршрутизатор
Вопрос:
Я пытаюсь использовать функциональные составные компоненты с помощью react-router. Каким будет тип Login.button в интерфейсе LoginComposition?
import React, { FC } from 'react';
import { Button } from '../../styles/login';
import { RouteComponentProps, withRouter } from 'react-router-dom';
interface LoginComposition {
Button: <INSERT TYPE HERE>;
}
const Login: FC amp; LoginComposition = ({ children }) => {
return <div>{children}</div>;
};
const LoginButton: FC<RouteComponentProps> = ({ children, history }) => {
return <Button onClick={() => history.push('foo')}>{children}</Button>;
};
Login.Button = withRouter(LoginButton);
export default Login;
Комментарии:
1. Вы можете использовать
function Login
вместоconst Login
и просто назначитьLogin.Button
, и в этом случае TypeScript автоматически определит правильный тип.
Ответ №1:
Сначала я отвечу на вопрос напрямую, затем я объясню способ избежать сумасшествия Typescript. Для чего-то подобного вам нужно изменить порядок определения типов и функций. Вы могли бы извлечь типы react-router
, которые генерирует пакет, и перепроектировать тип withRouter()
, но я проверил пакет, и он не симпатичный, и он не будет устойчивым, если тип изменится. Что вам нужно, так это немедленно обернуть LoginButton
withRouter(...)
или создать вторую переменную для ее хранения. Примеры здесь:
const LoginButton = withRouter(({ children, history }) => {
return <Button onClick={() => history.push('foo')}>{children}</Button>;
});
// OR
const LoginButton: FC<RouteComponentProps> = ({ children, history }) => {
return <Button onClick={() => history.push('foo')}>{children}</Button>;
};
const WrappedLoginButton = withRouter(LoginButton);
Затем последним шагом будет поместить Login
компонент и интерфейс под LoginButton
(или WrappedLoginButton
) и использовать typeof
для извлечения из него ввода. Вся настройка будет выглядеть следующим образом (с использованием WrappedLoginButton
)
import React, { FC } from 'react';
import { Button } from '../../styles/login';
import { RouteComponentProps, withRouter } from 'react-router-dom';
const LoginButton: FC<RouteComponentProps> = ({ children, history }) => {
return <Button onClick={() => history.push('foo')}>{children}</Button>;
};
const WrappedLoginButton = withRouter(LoginButton);
interface LoginComposition {
Button: typeof WrappedLoginButton;
}
const Login: FC amp; LoginComposition = ({ children }) => {
return <div>{children}</div>;
};
Login.Button = WrappedLoginButton;
export default Login;
Чтобы упростить код, есть ли причина, по которой вы не можете просто использовать useHistory()
хук? Особенно с Typescript, компоненты более высокого порядка могут быть довольно привередливыми. Если вы используете хук следующим образом:
const LoginButton: FC<RouteComponentProps> = ({ children }) => {
const history = useHistory();
return <Button onClick={() => history.push('foo')}>{children}</Button>;
};
Это уменьшит потребность в синтаксисе withRouter, что означает, что типы могут быть сведены к следующему:
import React, { FC } from 'react';
import { Button } from '../../styles/login';
import { RouteComponentProps, withRouter } from 'react-router-dom';
const LoginButton: FC<RouteComponentProps> = ({ children }) => {
const history = useHistory();
return <Button onClick={() => history.push('foo')}>{children}</Button>;
};
interface LoginComposition {
Button: typeof LoginButton;
}
const Login: FC amp; LoginComposition = ({ children }) => {
return <div>{children}</div>;
};
Login.Button = withRouter(LoginButton);
export default Login;