问答

ts中对高阶组件进行form注入报错

作者:admin 2021-04-21 我要评论

react@16.14.0 typescript@4.1.5 import React from "react";import { Form, FormInstance } from "antd";export interface InjectedWithFormProps { form: Form...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

react@16.14.0 typescript@4.1.5

import React from "react";
import { Form, FormInstance } from "antd";

export interface InjectedWithFormProps {
  form: FormInstance<any>;
}

export default function withForm<P extends InjectedWithFormProps>(WrappedComponent: React.ComponentType<P>) {
  return function WithForm(props: Subtract<P, InjectedWithFormProps>) {
    const [form] = Form.useForm();

    return <WrappedComponent form={form} {...props}></WrappedComponent>;
  };
}

Subtract 声明

declare type SetDifference<A, B> = A extends B ? never : A;

declare type SetComplement<A, A1 extends A> = SetDifference<A, A1>;

declare type Subtract<T extends T1, T1 extends object> = Pick<
  T,
  SetComplement<keyof T, keyof T1>
>;

上述代码是用antd v4的form进行注入,用来解决class form ref 在第一次render阶段拿不到form实例的问题,采用的是v4 版本 form 在 class 模式下,无法立即获得 formRef.current,注入form的类型写法参考了【译】TypeScript中的React高阶组件,但是对组件进行form注入约束的时候会报错
image.png

查了相关文档也没找到好的解决方案,不知道是不是typescript的bug
Invalid "could be instantiated with a different subtype of constraint" error
How to fix TS2322: “could be instantiated with a different subtype of constraint 'object'”?

###

你的问题可以简化为:

type Foo = {
    a: number;
    b: string;
}
function test<T extends Foo>(v: Omit<T, 'a'>): T {
    const ret = {
        ...v,
        a: 1
    };
    return ret; // Type 'Omit<T, "a"> & { a: number; }' is not assignable to type 'T'.
}

本质来说,就是因为你忽略 T 类型中的一个 key,然后再用 & 操作补充这个 key,TS 只认为这个类型是 T 的限制类型即 Foo 的合法子类型,但是和 T 类型本身并不是完全等价的,而实际 T 可能是 Foo 类型的任意子类型,可能比 'Omit<T, "a"> & { a: number; }' 包含更多的细节,因此类型不匹配。

试想如果我这样调用你的函数:

test<{a: 5, b: string}>({b: 'lalala'});

T 实际为 {a:5, b: string} 是 Foo 的子类型,而你的返回值显然不符合 T 类型,这就矛盾了,这说明你的 test 函数类型设计存在漏洞,TS 自然就把这个错误报出来让你修正了。

所以,现阶段要解决这个问题,就只能 as 大法了,你说它是这个类型那就是,你自己 js 层面保证没问题, TS 就不管你了。

export interface InjectedWithFormProps {
  form: FormInstance<any>;
}

export default function withForm<P extends InjectedWithFormProps>(WrappedComponent: React.ComponentType<P>) {
  return function WithForm(props: Omit<P, 'form'>) {
    const [form] = Form.useForm();
    const combinedProps = {
        form,
        ...props
    } as P;
    return <WrappedComponent {...combinedProps}></WrappedComponent>;
  };
}

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • ts中对高阶组件进行form注入报错

    ts中对高阶组件进行form注入报错

  • echarts标线

    echarts标线

  • ios微信端视频无法自动播放,需要触发p

    ios微信端视频无法自动播放,需要触发p

  • springboot是否没有父子容器的概念了?

    springboot是否没有父子容器的概念了?

腾讯云代理商
海外云服务器