TypeScript + React 类型安全三件套:Component、Redux、和Service类型化。html
首先安装React类型依赖:react
// React源码改成TypeScript以前都要手动安装这些类型依赖
npm i -D @types/react @types/react-dom
复制代码
React.ComponentType<P> = React.ComponentClass<P> | React.FunctionComponent<P>
npm
只有组件类型【html标签字符串除外】能够建立 JSX.Element
,示例:redux
// 正确
const C = () => <></>;
const thisIsJSX = <C />;
// 报错
const D = () => [<></>];
const throwError = <D />;
复制代码
所以当咱们须要经过props传递一个组件的时候,须要定义:安全
interface Props {
/** 自定义渲染组件 */
Cp: React.ComponentType<any>;
}
复制代码
进而才能在接收该属性的组件里:bash
props => {
const { Cp } = props;
return <Cp />;
}
复制代码
React.FunctionComponent<Props, Context>
或者 React.StatelessComponent<Props, Context>
, 可简写为 React.FC
或者React.SFC
。React Hooks出现以后,React.StatelessComponent
和 React.SFC
被标记为“不建议使用”。react-router
对应返回值必须是 JSX.Element
,示例:less
// 如下是函数式组件
const ThisIsFC = () => <></>;
function ThisIsFCToo() {
return <></>;
}
// 如下不是函数式组件
const ThisNotFC = () => [<></>];
function ThisIsNotFCNeither() {
return [<></>];
}
复制代码
React.ComponentClass<Props, State, Context>
, 继承 React.Component
或者 React.PureComponent
,示例:dom
const C: React.ComponentClass = xxxxx;
const jsx = <C />;
复制代码
对应的是 React.ElementType<P>
,等价的 React.ReactType
已被标记为“不建议使用”。函数
JSX.Element = React.ElementType<any>
以函数式组件为例,定义:
type Props = xxxxxxx;
const ThisIsFC: React.FC<Props> = props => <></>;
复制代码
其中 Props
能够分红如下即个子集,分别是:
OwnProps
,即建立 JSX <ThisIsFC ... />
直接传递的属性StateProps
,即经过 connect 到 redux store 获取的属性DispatchProps
,也是经过 connect 到 redux 获取的属性RouteProps
,即经过 react-router-dom Route 路由传递的属性因此:
Props = OwnProps & RouteProps & StateProps & DispatchProps;
复制代码
OwnProps
和 RouteProps
类型:interface OwnProps {
/** name */
name: string;
}
import { RouteComponentProps } from 'react-router-dom';
type RouteProps = RouteComponentProps<{ id: string }>;
复制代码
如此,咱们能够在组件内部:
const ThisIsFC = props => {
{
const { id } = props.match.params;
// 正确
cosnt str: string = id;
// 报错
const num: number = id;
}
{
const { name } = props;
// 正确
cosnt str: string = id;
// 报错
const num: number = id;
}
return <></>;
}
复制代码
StateProps
& DispatchProps
是不能手写的,由于彻底能够经过 map* 函数推断出来。
推断StateProps
:
type StateProps = ReturnType<typeof mapStateToProps>;
// TODO: Redux 类型化
function mapStateToProps(state: IRootState) {
return {
user: state.xxx.xxx
};
}
复制代码
推断DispatchProps
:
import { bindActionCreators, Dispatch } from 'redux';
// TODO: Redux 类型化
import actions from '../redux/actions';
type DispatchProps = ReturnType<typeof mapDispatchToProps>;
function mapDispatchToProps(dispatch: Dispatch) {
return {
actions: bindActionCreators(actions, dispatch)
};
}
复制代码
如此,咱们能够在组件内部:
const ThisIsFC = props => {
props.user;
props.actions.doSomething;
return <></>;
}
复制代码
import { connect } from 'react-redux';
export default connect<StateProps, DispatchProps, OwnProps>(
mapStateToProps,
mapDispatchToProps
)(ThisIsFC);
复制代码
以上一样适用于类组件,只是类组件会多出一个 State
类型设置。
定义泛型组件
function ThisIsGenericFC<P extends string | number>(props: Props<P>) {}
class ThisIsGenericComponent<P extends string | number> extends React.Component<Props<P>, State> {}
const jsxFC = <ThisIsGenericFC<string> />;
const jsxComponent = <ThisIsGenericComponent<number> />;
复制代码
下一节“Redux 类型化”。