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 類型化」。