You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在HOC自身组件与泛型子组件间拆分泛型Props?

解决React HOC中泛型组件的类型断言问题

问题根源

你遇到的错误是因为TypeScript无法确认{errorMessage: string} & Omit<...>完全匹配泛型类型P——P作为EditorFieldsProps的子类型,可能包含更严格的类型约束(比如errorMessage被定义为特定字面量类型),导致自动推断的类型无法满足子类型要求。

解决方案:拆分泛型参数明确职责

通过将组件props拆分为用户自定义部分和HOC提供部分,让TypeScript清晰识别类型兼容性,彻底移除类型断言:

import * as React from 'react';
import { render } from 'react-dom';

// HOC提供的固定props
interface EditorFieldsProps {
  errorMessage: string;
}

// 编辑器组件需要接收的通用props
interface EditorProps {
  disabled: boolean;
  onSubmit: () => void;
}

// 重新定义HOC:拆分泛型参数,明确区分用户自定义props(T)和HOC提供的props(EditorFieldsProps)
function withEditor<T>(EditorFields: React.FC<T & EditorFieldsProps>) {
  // HOC返回的组件接收:用户自定义props(T) + 编辑器通用props(EditorProps)
  return function (props: T & EditorProps) {
    const { onSubmit, disabled, ...rest } = props;
    const errorMessage = 'Uh oh.'; // 实际场景可替换为验证结果
    
    // 无需类型断言:rest是T,加上errorMessage正好匹配EditorFields需要的T & EditorFieldsProps
    return (
      <form onSubmit={onSubmit}>
        <EditorFields {...rest} errorMessage={errorMessage} />
        <input type="submit" disabled={disabled} />
      </form>
    );
  };
}

// 自定义的Person编辑器props
interface PersonEditorFieldsProps {
  person: Person;
  onChange: React.ChangeEventHandler<HTMLInputElement>;
}

// 编辑对象类型
interface Person {
  fullName: string;
}

// 渲染编辑字段的组件(无需继承EditorFieldsProps,由HOC自动注入)
function PersonEditorFields(props: PersonEditorFieldsProps & EditorFieldsProps) {
  const { person, onChange, errorMessage } = props;
  return (
    <div>
      <input value={person.fullName} onChange={onChange} />
      <div style={{ color: errorMessage ? 'red' : 'green' }}>
        {errorMessage ? errorMessage : 'No errors!'}
      </div>
    </div>
  );
}

// 生成最终的编辑器组件
const PersonEditor = withEditor(PersonEditorFields);

function App() {
  const [person, setPerson] = React.useState<Person>({ fullName: 'Smith' });
  return (
    <PersonEditor
      person={person}
      onChange={(event) => setPerson({ fullName: event.target.value })}
      onSubmit={() => alert(`Submitting ${person.fullName}`)}
      disabled={false}
    />
  );
}

render(<App />, document.getElementById('root'));

核心改进点

  • 泛型拆分:将原有的单一泛型P拆分为T(用户自定义props),明确EditorFields的props是T与EditorFieldsProps的交集,避免子类型兼容问题。
  • 类型推断清晰:HOC返回的组件接收T & EditorProps,解构后rest直接对应T,加上HOC提供的errorMessage,完全匹配EditorFields的props要求,TypeScript可自动验证类型。
  • 代码更简洁:移除冗余的CustomFieldsProps类型定义,无需手动计算排除字段。

额外优化

你可以把PersonEditorFieldsProps & EditorFieldsProps抽离为通用类型,进一步简化组件定义:

type WithEditorFieldsProps<T> = T & EditorFieldsProps;

function PersonEditorFields(props: WithEditorFieldsProps<PersonEditorFieldsProps>) {
  // ...组件逻辑不变
}

内容的提问来源于stack exchange,提问作者Carl G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:25:22