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

如何为React.memo包装的组件添加静态属性并实现TypeScript类型推断

问题描述

核心问题

给普通函数添加额外属性时,TypeScript能自动推断属性类型;但给React.memo返回的组件添加额外属性时,TypeScript无法自动推断类型。

示例代码:

// 期望像给foo添加属性一样,给Foo = React.memo(foo)实现相同的类型推断
const Foo = React.memo(foo)

Foo.cssset = {
  root: css``,
  bar: css``,
}

Foo.cssset // 期望类型为 { root: number, bar: number }
  //^?
Foo.cssset.root // 期望类型为 number
         //^?

2023/08/10 更新需求

希望给React.memo包装后的组件配置静态属性(如内部使用的CSS类名),实现:

  • 组件内部能直接通过组件名访问静态属性
  • 外部(如设计师)只需记住导出的组件名,就能直接获取静态属性,无需额外导入原始函数

期望实现的代码结构:

export const Foo = React.memo(() => {
  return (
    <div css={[Foo.cssset.root]}>
      <div css={[Foo.cssset.areas.filter]}>
        <SimulatedButton />
        <SymbolSelector />
      </div>
      <div css={[Foo.cssset.areas.status]}>
        <OverviewsStatus />
      </div>
      <div css={[Foo.cssset.areas.list]}>
        <DataList />
      </div>
    </div>
  )
})

Foo.cssset = {
  root: 'root-fj289uf',
  areas: {
    filter: 'filter-fjiu128',
    status: 'filter-fkj2if8',
    list: 'filter-vjk38f',
  },
}

设计师使用场景:

<div
  id='layout'
  css={css`
    .${Foo.cssset.root} {
      // 直接通过导出的组件名访问静态属性
    }
  `}
></div>
解决方案

方法一:手动扩展组件类型

先定义静态属性的类型,再通过类型断言给React.memo返回的组件扩展类型:

import React from 'react'

// 定义cssset的类型
type CssSet = {
  root: string
  areas: {
    filter: string
    status: string
    list: string
  }
}

// 定义带静态属性的组件类型
type MemoComponentWithCssSet = React.FC & { cssset: CssSet }

// 创建组件并赋值静态属性
export const Foo = React.memo(() => {
  return (
    <div css={[Foo.cssset.root]}>
      <div css={[Foo.cssset.areas.filter]}>
        <SimulatedButton />
        <SymbolSelector />
      </div>
      <div css={[Foo.cssset.areas.status]}>
        <OverviewsStatus />
      </div>
      <div css={[Foo.cssset.areas.list]}>
        <DataList />
      </div>
    </div>
  )
}) as MemoComponentWithCssSet

// 赋值静态属性,TypeScript会自动校验类型
Foo.cssset = {
  root: 'root-fj289uf',
  areas: {
    filter: 'filter-fjiu128',
    status: 'filter-fkj2if8',
    list: 'filter-vjk38f',
  },
}

方法二:使用工具函数自动推断类型

如果不想手动定义CssSet类型,可以写一个工具函数自动推断静态属性类型,同时保留组件原有类型:

import React, { memo, FC } from 'react'

// 工具函数:给memo组件添加静态属性并自动推断类型
function memoWithStaticProps<T extends FC, S>(Component: T, staticProps: S): T & S {
  const Memoized = memo(Component)
  Object.assign(Memoized, staticProps)
  return Memoized as T & S
}

// 使用工具函数创建组件
export const Foo = memoWithStaticProps(() => {
  return (
    <div css={[Foo.cssset.root]}>
      <div css={[Foo.cssset.areas.filter]}>
        <SimulatedButton />
        <SymbolSelector />
      </div>
      <div css={[Foo.cssset.areas.status]}>
        <OverviewsStatus />
      </div>
      <div css={[Foo.cssset.areas.list]}>
        <DataList />
      </div>
    </div>
  )
}, {
  cssset: {
    root: 'root-fj289uf',
    areas: {
      filter: 'filter-fjiu128',
      status: 'filter-fkj2if8',
      list: 'filter-vjk38f',
    },
  }
})

方法三:简化类型断言实现

如果仅给单个组件添加属性,可直接用类型断言扩展,无需额外工具函数:

import React from 'react'

export const Foo = React.memo(() => {
  return (
    <div css={[(Foo as React.FC & { cssset: CssSet }).cssset.root]}>
      <div css={[(Foo as React.FC & { cssset: CssSet }).cssset.areas.filter]}>
        <SimulatedButton />
        <SymbolSelector />
      </div>
      {/* ...其他内容 */}
    </div>
  )
})

// 给组件添加静态属性并指定类型
type CssSet = {
  root: string
  areas: {
    filter: string
    status: string
    list: string
  }
}
(Foo as React.FC & { cssset: CssSet }).cssset = {
  root: 'root-fj289uf',
  areas: {
    filter: 'filter-fjiu128',
    status: 'filter-fkj2if8',
    list: 'filter-vjk38f',
  },
}
关键原理

React.memo返回的类型是React.MemoExoticComponent<T>,默认不包含自定义静态属性。通过**类型交集(&)**将组件类型与静态属性类型合并,即可让TypeScript识别自定义属性。工具函数方式通过泛型自动推断静态属性类型,减少手动定义的工作量。

内容的提问来源于stack exchange,提问作者Triple Top Patterns

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:07:31