TypeScript 和 React:组合高阶组件
TypeScript & React: compose higher-order components
我是 TypeScript 和 React 的新手,我(已经)在 React 中有两个 HOC,我想 compose
它们,因为很可能会有更多。
import { getIsAuthenticated } from 'features/user-authentication/user-authentication-reducer';
import { connect, ConnectedProps } from 'react-redux';
import { RootState } from 'redux/root-reducer';
import { withTranslation } from '../../../i18n';
import HomePageComponent from './home-page-component';
const mapStateToProps = (state: RootState) => ({
isAuthenticated: getIsAuthenticated(state),
});
const connector = connect(mapStateToProps);
export type PropsFromRedux = ConnectedProps<typeof connector>;
export default withTranslation()(connector(HomePageComponent));
这就是它目前的样子(和工作/编译)。组件是:
// ...
import { TFunction } from 'next-i18next';
// ...
import { PropsFromRedux } from './home-page-container';
type Props = {
readonly t: TFunction;
} & PropsFromRedux;
const HomePageComponent = ({ isAuthenticated, t }: Props) => (
// ...
在JavaScript我通常这样做:
export default compose(withTranslation(), connector)(HomePageComponent);
其中 compose
来自 Ramda 或来自 Redux 本身。
使用 Ramda 的 compose
会抛出两个错误。
connector
: No overload matches this call.
HomePageComponent
: Expected 0 arguments, but got 1.
使用 Redux' compose
在这里编译,但破坏了我的测试。
import { render, screen } from 'tests/test-helpers';
import HomePageContainer from './home-page-container';
describe('Home Page Container', () => {
it('should render a greeting', () => {
render(<HomePageContainer />);
expect(screen.getByText(/hello world/i)).toBeInTheDocument();
});
});
在测试文件中,HomePageContainer
抛出:
JSX element type 'HomePageContainer' does not have any construct or call signatures.
如何将 compose
用于高阶组件并让它与 TypeScript 一起工作?
PS: 我在 SO 中找到了 其他问题和答案,但答案在最新的 TS 版本中不起作用,并且仅适用于对于两个 HOC,我需要编写更多。
我的tsconfig.json
:
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "./src",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "preserve",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "es5"
},
"exclude": ["node_modules"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}
CodeSandbox 中的最小示例:https://codesandbox.io/s/hoc-breaking-example-mtp3m
如果你去 rambda compose
输入你会看到它是通用的,所以你可以定义结果函数,像这样输入它可以消除错误
export default compose<React.FunctionComponent>(
withTitle("Hello Whosebug!"),
connector
)(App);
我是 TypeScript 和 React 的新手,我(已经)在 React 中有两个 HOC,我想 compose
它们,因为很可能会有更多。
import { getIsAuthenticated } from 'features/user-authentication/user-authentication-reducer';
import { connect, ConnectedProps } from 'react-redux';
import { RootState } from 'redux/root-reducer';
import { withTranslation } from '../../../i18n';
import HomePageComponent from './home-page-component';
const mapStateToProps = (state: RootState) => ({
isAuthenticated: getIsAuthenticated(state),
});
const connector = connect(mapStateToProps);
export type PropsFromRedux = ConnectedProps<typeof connector>;
export default withTranslation()(connector(HomePageComponent));
这就是它目前的样子(和工作/编译)。组件是:
// ...
import { TFunction } from 'next-i18next';
// ...
import { PropsFromRedux } from './home-page-container';
type Props = {
readonly t: TFunction;
} & PropsFromRedux;
const HomePageComponent = ({ isAuthenticated, t }: Props) => (
// ...
在JavaScript我通常这样做:
export default compose(withTranslation(), connector)(HomePageComponent);
其中 compose
来自 Ramda 或来自 Redux 本身。
使用 Ramda 的 compose
会抛出两个错误。
connector
:No overload matches this call.
HomePageComponent
:Expected 0 arguments, but got 1.
使用 Redux' compose
在这里编译,但破坏了我的测试。
import { render, screen } from 'tests/test-helpers';
import HomePageContainer from './home-page-container';
describe('Home Page Container', () => {
it('should render a greeting', () => {
render(<HomePageContainer />);
expect(screen.getByText(/hello world/i)).toBeInTheDocument();
});
});
在测试文件中,HomePageContainer
抛出:
JSX element type 'HomePageContainer' does not have any construct or call signatures.
如何将 compose
用于高阶组件并让它与 TypeScript 一起工作?
PS: 我在 SO 中找到了
我的tsconfig.json
:
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "./src",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "preserve",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "es5"
},
"exclude": ["node_modules"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}
CodeSandbox 中的最小示例:https://codesandbox.io/s/hoc-breaking-example-mtp3m
如果你去 rambda compose
输入你会看到它是通用的,所以你可以定义结果函数,像这样输入它可以消除错误
export default compose<React.FunctionComponent>(
withTitle("Hello Whosebug!"),
connector
)(App);