class 类型

React.Ref> === React.Ref
class 直接作为泛型参数似乎会被处理为InstanceType,而 typeof XXclass,反而能真正获取 class的类型。

HOC 后的 ref 类型

场景

HOC 包裹后的组件,不可直接ref获取,因为此时获取的是包裹用组件,入需获取内部组件,通用且兼容的方式就是采取 易名props 来承载 ref,再在包裹用组件内将其通过 ref={易名props} 的方式将其放置在真正需要取的组件的 ref 上。
但因为 react 组件嵌套的类型自推导在当前的 typescript 中无法实现,所以只能曲线救国,过程类似下面的各种断言操作。
HOC之所以可以 compose 是因为接受了环境参数后的 (C: Component<..>)=> Component<..>,确实是进入及返回都是同一样’东西’,只是 props 变得不一样了,所以会无法通过当前的 ts 检查。

组件类型:
compose函数组装 HOC,并自制返回组件的类型,这里需要小心,瞎写的类型会给外部带来很大的误导:
这里实际承载 ref 的是props: wrappedComponentRef,例子来自 antd3.x Form.create

  1. const WrappedComponent = compose<
  2. React.ComponentClass<
  3. PropsNeeded & {
  4. // wrappedComponentRef: React.ClassAttributes<Test>['ref'];
  5. wrappedComponentRef: React.Ref<Test>;
  6. }
  7. >
  8. >(
  9. formWrapper,
  10. connector,
  11. )(Test);

React.Ref 生成的类型形状就类似于在 jsx 上写上的 ref 的形状:
image.png
提取泛型及提取过程
这里的过程也是模仿的 React.ElementRef 从 ref 中提取 Instance 的过程,无非就是 原本 react 从组件 class 的 ‘ref’ 属性上 infer,而现在需要从易名 Props 上infer了:

  1. type PropsRef<T> = NonNullable<T> extends React.Ref<infer Instance>
  2. ? Instance
  3. : never;
  4. const componentRef = React.useRef<
  5. PropsRef<
  6. React.ComponentPropsWithoutRef<
  7. typeof WrappedComponent
  8. >['wrappedComponentRef']
  9. >
  10. >(null!);

image.png
以及使用泛型完整推导:

  1. type PropsForwardElementRef<
  2. C extends
  3. | React.ForwardRefExoticComponent<any>
  4. | { new (props: any): React.Component<any> }
  5. | ((props: any, context?: any) => React.ReactElement | null)
  6. | keyof JSX.IntrinsicElements,
  7. T
  8. > = T extends keyof React.ComponentPropsWithoutRef<C>
  9. ? NonNullable<React.ComponentPropsWithoutRef<C>[T]> extends React.Ref<
  10. infer Instance
  11. >
  12. ? Instance
  13. : never
  14. : never;
  15. // 从 WrappedComponent 组件中 取到从 wrappedComponentRef 这个 props 挂载的 ref
  16. const componentRef = React.useRef<
  17. PropsForwardElementRef<typeof WrappedComponent, 'wrappedComponentRef'>
  18. >(null!);

与其实现自推导,还不如实现更加合适的断言。
一些解决方案:
https://stackoverflow.com/questions/54355096/how-to-use-hoc-with-redux-compose-and-typescript
https://rjzaworski.com/2017/09/typescript-react-compose
https://dev.to/ascorbic/creating-a-typed-compose-function-in-typescript-3-351i