TypeScript + React最佳實踐-Component類型化

前言

TypeScript + React 類型安全三件套:Component、Redux、和Service類型化。html

Component類型化

首先安裝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.StatelessComponentReact.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>

組件類型化

props類型化

以函數式組件爲例,定義:

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;
複製代碼

定義 OwnPropsRouteProps 類型:

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

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

相關文章
相關標籤/搜索