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

如何在React高阶组件中保留泛型类型

React高阶组件保留泛型的实现方案

场景说明

使用React高阶组件模式时,需要在Props传入目标组件前对部分Props做转换处理:

  • 上游传入的Props中foo、bar为可选字段
  • 转换后传入内部组件的下游Props中foo、bar、bix为必填字段
  • 内部组件本身是泛型组件,包装后需要保留泛型能力

基础类型与转换逻辑如下:

type UpstreamProps<X> = {
    foo?: number
    bar?: string
    baz:  X
}

type DownstreamProps<X> = {
    foo: number
    bar: string
    baz: X
    bix: string
}

function transform<X>(props: UpstreamProps<X>): DownstreamProps<X> {
    return {
        ...props,
        foo: props.foo || 0,
        bar: props.bar || '(unknown)',
        bix: `${props.foo}-${props.bar}-bix`
    }
}

内部组件使用严格的下游Props类型定义:

function Parent<X>(props: DownstreamProps<X> & {formatter: (x: X) => string}) {
    return (
        <>
            foo = {props.foo}
            bar = {props.bar}
            baz = {props.formatter(props.baz)}
            bix = {props.bix}
        </>
    )
}

调用包装后的组件时,只需要传入上游可选Props,同时支持指定泛型参数:

<WrappedParent<number>
    baz={22}
    formatter={(x: number) => `my number squared is ${Math.pow(x, 2)}`}
/>

初始写法的问题在于HOC调用时就把泛型参数固化,导致包装后的组件丢失泛型能力,同时需要同时满足两个约束:

  • 传入不符合要求的组件(Props不包含DownstreamProps所有字段)给withUpstreamProps时,必须抛出类型错误
  • 包装后的组件支持单泛型参数调用,如WrappedParent<number>

最终实现

import React from 'react';

function withUpstreamProps<P extends DownstreamProps<any>>(
    WrappedComponent: React.ComponentType<P>
) {
    // 返回独立的泛型函数组件,不在HOC调用阶段固化泛型
    const Wrapped = <X,>(
        props: Omit<P, keyof DownstreamProps<X>> & UpstreamProps<X>
    ) => {
        const { foo, bar, baz, ...rest } = props;
        const transformedProps = transform({foo, bar, baz});
        return <WrappedComponent {...transformedProps} {...(rest as any)} />
    };
    return Wrapped;
}

// 直接包装即可,不需要额外传泛型
const WrappedParent = withUpstreamProps(Parent);

实现逻辑说明

  1. 入参合法性校验:通过P extends DownstreamProps<any>约束传入的组件必须接收DownstreamProps的所有字段,传入不相关的随机组件时TypeScript会直接报类型错误,满足第一个约束。
  2. 泛型能力保留:返回的包装组件本身是独立泛型组件,泛型参数X在组件调用阶段才会被推导,不会在HOC执行阶段被固化,因此支持WrappedParent<number>这类单泛型调用写法。
  3. 类型自动合并:通过Omit<P, keyof DownstreamProps<X>> & UpstreamProps<X>自动计算包装后组件的Props类型:将原组件中属于下游Props的部分替换为上游可选Props,组件自带的其他自定义Props(比如示例中的formatter)会完整保留,类型推导完全自动,不需要手动声明额外类型。

提示:如果使用TypeScript 4.7以下版本,泛型箭头函数需要在泛型参数后加逗号(即<X,>写法)避免和JSX语法冲突,高版本可直接写<X>。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:36:18