react+ts

  1. react.FC 和 normal function 区别

    • react.FC

      type FC<P = {}> = FunctionComponent<P>
      type PropsWithChildren<P> = P & { children?: ReactNode }
      interface FunctionComponent<P = {}> {
      (props: PropsWithChildren<P>, context?: any): ReactElement<
      any,
      any
      > | null
      propTypes?: WeakValidationMap<P>
      contextTypes?: ValidationMap<any>
      defaultProps?: Partial<P>
      displayName?: string
      }

    Create-react-app 从模板中删除 React.FC

    https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components

    使用 FC 需要注意:

    • 组件 defaultProps 使用 es6 方式
    • 无法使用泛型
    • 返回类型是 ReactElement 和 null(不包含 undefined,string 等)

    尽量不要指定组件的 return 类型(ReactNode 或者 JSX.Element),而是让 ts 自己去推断。

  2. hooks

    • 类型会自动推断

    • 初始值是 null 使用联合类型 useState<P | null>(null)

    • useRef\<HTMLElement>(null!) or useRef\<HTMLElement | null>(null)

      尽量不用!(Non-null、Non-undefined),而是使用非 null 后者非 undefined 代码块。程序更易读

    • 自定义 hooks 注意返回值的类型推断

      export function useLoading() {
      const [isLoading, setState] = React.useState(false)
      const load = (aPromise: Promise<any>) => {
      setState(true)
      return aPromise.finally(() => setState(false))
      }
      return [isLoading, load] as const // infers [boolean, typeof load] instead of (boolean | typeof load)[]
      }
      • When declaring a mutable variable or property, TypeScript often widens values to make sure that we can assign things later on without writing an explicit type.

        在声明可变变量或属性时,TypeScript 通常会加宽值,以确保以后可以分配内容而无需编写显式类型

      • 使用 const 断言,将 literal types 、object literals、array literals 变成 readonly

  3. defaultProps 使用方式

    fc 和 class 组件使用 defaultProps

    • 函数式组件尽量使用 es6 默认赋值
  4. type or interface

    能使用 interface 就是用 interface,库中 interface 方便重载

    具体区别请看《重拾 ts》中两个对比

  5. prop types

    1. Basic prop types
    1. Useful prop types

      • JSX.Element orJSX.Element[]
      • React.ReactChildren or React.ReactChild[] or React.ReactNode
      • React.CSSProperties指定 style 对象

      注意:请查看《重拾 ts》JSX.Element 和 React.ReactNode 的对比

  6. JSX.Element vs React.ReactNode vs React.ReactElement

    • JSX.Element -> Return value of React.createElement
    • React.ReactNode -> Return value of a component
    declare namespce React {
    interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
    type: T;
    props: P;
    key: Key | null;
    }
    type ReactText = string | number;
    type ReactChild = ReactElement | ReactText;
    interface ReactNodeArray extends Array<ReactNode> {}
    type ReactFragment = {} | ReactNodeArray;
    type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
    }
    declare global {
    namespace JSX {
    interface Element extends React.ReactElement<any, any> { }
    }
    }

    从上面可以看出,ReactElement 和 JSX.Element 基本类似。ReactNode 类型更多

什么时候使用 JSX.Element vs ReactNode vs ReactElement?

  1. class component

  2. getDerivedStateFromProps

  3. context

  4. forwardRef/createRef

  5. class 组件中 createRef 必须指定具体的元素。

    class CssThemeProvider extends React.PureComponent<Props> {
    private rootRef = React.createRef<HTMLDivElement>() // like this
    render() {
    return <div ref={this.rootRef}>{this.props.children}</div>
    }
    }
  6. forwardRef

React Refs with TypeScript

  1. Portals

参考