当前位置: 首页 > 知识库问答 >
问题:

react.js - 如何在ts中使用拓展运算符组合泛型变量?

小牛23149
2024-07-30

我写了一个react 高阶组件 简化后形如


type Props<T> = {
  value: T
}

function HOC<P extends Props<any>>(Comp: ComponentType<P>) {
  type ValueType = P extends Props<infer T> ? T : never
  type Example = Omit<P, 'value'> & { value1: ValueType }

  return function CompWithHOC(props: Example) {
    const { value1, ...rest } = props
    const compProps: P = { // here
      ...rest,
      value: value1
    }
    return <Comp {...compProps}></Comp>
  }
}

但 compProps处有类型错误 不能将字面量识别为P 报错为
不能将类型“Omit<Example, "value1"> & { value: ValueType; }”分配给类型“P”。
"Omit<Example, "value1"> & { value: ValueType; }" 可赋给 "P" 类型的约束,但可以使用约束 "Props<any>" 的其他子类型实例化 "P"。

我希望学习如何在ts中使用拓展运算符展开和组合变量 以及高阶组件的写法

补充:
1.上述代码是简化后的结果 仅取基本含义 不代表实际内容
2.P extends Props<any>是必要的 因为被修饰的组件可能具有其他参数 且我希望能从参数中自动获取类型(目前还没找到更好的写法)
3.ai建议的rest as Omit<P, 'value'>已经试过 没有意义.目前尝试这一行上的类型断言都不生效

共有2个答案

郎泰平
2024-07-30
type Props<T> = {
    value: T
}

function HOC<T>(Comp: ComponentType<Props<T>>) {
    type Example = { value1: T }

    return function CompWithHOC(props: Example) {
        const { value1, ...rest } = props
        const compProps: Props<T> = {
            ...rest,
            value: value1
        }
        return <Comp {...compProps}></Comp>
    }
}
呼延鸿畅
2024-07-30

在 TypeScript 中,当你使用高阶组件(HOC)并且涉及到泛型时,确保类型的正确性和兼容性是非常重要的。在你的例子中,你遇到了一个类型推断的问题,这是因为 TypeScript 的类型系统无法直接确定 P 的确切类型,尤其是在你尝试将 props 转换为 P 类型时。

问题在于 rest 的类型是 Omit<Example, "value1">,它只保证了除 value1 外的所有属性都存在于 P 中,但并没有保证 P 可能包含的其他非 value 属性也存在。此外,ValueType 是从 P 推断出来的,但它可能与 Pvalue 的实际类型不完全一致(尽管在你的例子中,由于 P 继承自 Props<any>,这通常不是问题)。

要解决这个问题,你可以通过显式地转换 restvalue1 来创建一个新的对象,这个对象的类型兼容 P。这里的关键是理解 TypeScript 的类型兼容性是基于结构子类型的,所以只要对象的形状匹配,就可以被当作另一种类型。

这里是一个修改后的版本,它使用了类型断言来确保类型兼容性:

import React, { ComponentType, PropsWithChildren } from 'react';

type Props<T> = {
  value: T;
}

function HOC<P extends Props<any>>(Comp: ComponentType<P>) {
  type ValueType = P extends Props<infer T> ? T : never;
  type Example = Omit<PropsWithChildren<P>, 'value'> & { value1: ValueType }; // 使用 PropsWithChildren 以支持 children

  return function CompWithHOC(props: Example) {
    const { value1, ...rest } = props;

    // 创建一个新对象,其类型被断言为 P
    const compProps = {
      ...rest as Omit<P, 'value'>, // 显式地断言 rest 为 P 中除 value 外的部分
      value: value1 as P['value']  // 显式地断言 value1 为 P 中 value 的类型
    } as P; // 最后将整个对象断言为 P 类型

    return <Comp {...compProps} />;
  }
}

// 使用示例
interface MyComponentProps extends Props<string> {
  extraProp: number;
}

const MyComponent: React.FC<MyComponentProps> = ({ value, extraProp }) => (
  <div>{value} - {extraProp}</div>
);

const EnhancedMyComponent = HOC(MyComponent);

// 渲染
const App = () => (
  <EnhancedMyComponent value1="Hello" extraProp={42} />
);

注意几个关键点:

  1. 我使用了 PropsWithChildren 而不是 P 直接在 Omit 中,这是因为高阶组件通常应该支持子元素(children)。
  2. 我添加了类型断言来确保 restvalue1 能够正确地被当作 P 类型的一部分。
  3. 在最后的对象上我也使用了类型断言 as P,以确保整个对象符合 P 的类型要求。

这样修改后,你的高阶组件应该能够正确地处理泛型类型 P,并且在 TypeScript 中不会出现类型错误。

 类似资料:
  • 问题内容: 我想对两个均扩展Number的相同类型的泛型参数执行操作。 可能吗?我一直习惯在泛型参数上调用方法,但使用运算符似乎存在一些问题(对于参数T,T,运算符+未定义)。 我究竟做错了什么? 编辑:我试图改善我的问题。我知道没有为Number类型定义运算符。这件事有点可悲,因为在不引入@Victor Sorokin建议的新接口的情况下执行这样的操作会很好。 但是我仍然不明白一件事:如果没有在

  • 问题内容: 除了Swift,我还有这个问题。如何Type在泛型中使用变量? 我尝试了这个: This didn’t work either: 有没有办法做到这一点?我感觉到Swift只是不支持 它,并且给了我一些模棱两可的错误消息。 编辑:这是一个更复杂的示例,其中无法 使用通用函数标头来解决问题。当然,这没有任何意义, 但是我在代码中的某处合理地使用了这种功能 ,宁愿发布一个干净的示例而不是我的

  • 问题内容: 在Java中,协方差允许API设计人员指定实例可以概括为某种类型或该类型的子类型中的任何一种。例如: 相反,则相反。它允许我们指定实例可以被概括为某种类型或超类型。 Java泛型的矛盾性如何有用?您何时选择使用它? 问题答案: 好吧,您的第二个示例将允许您编写: 而您无法使用第一种形式执行此操作。它不会像协方差那样有用,我将授予您。 在比较方面,它 可能 是有用的一个领域。例如,考虑:

  • 我有一个具有两个数据成员的泛型类。这是我写的一段代码 我想对num1和num2进行简单的算术运算,比如加法和减法,我还想进行简单的二进制运算,比如 但是这是不允许的,那么有人能告诉我如何执行这些任务吗?

  • 问题内容: 我已经安装了模块。 模式集为。要使用它,我必须运行以下选择: 我正在尝试使用运算符运行一条语句,并收到以下消息。 运行或操作员需要什么? 问题答案: 这很可能是的问题。run: 是否包含安装pg_trgm的架构?如果没有,请包括在内。 另外,您可以使用结构对函数进行模式限定-甚至运算符: 使它独立于。

  • 问题内容: 我有和数组两个值,我想在选择查询中将它与sql IN运算符一起使用。 这是我桌子的结构 我有两个值的数组 我想获取comp_id 1和comp_id 2的记录。因此,我编写了以下查询。 但是它不会返回结果。 问题答案: 由于您拥有普通 整数 就可以做到… (由于不断出现,一些其他信息…) 如果使用 字符串 (特别是 不受信任的 )输入,可以做到 但不能处理NULL之类的值。并会添加引号