TypeScript中如何定义Foo、Foo.Bar形式的React组件
TypeScript 实现React组件点语法访问静态子组件
报错原因
直接给React.FC类型声明的组件挂载额外属性时,TS会检测到当前组件类型定义中不存在对应属性,因此抛出类型错误。本质是默认的函数组件类型没有预定义你要挂载的静态子组件属性类型。
修复方案
方案1:交叉类型扩展组件类型
通过交叉类型给组件补充静态属性的类型定义,是最通用的实现方式:
import React from 'react'; interface IFooProps { title: string } interface IBarProps { content: string } // 定义Foo组件的完整类型:本身是接收IFooProps的函数组件,额外携带Bar子组件属性 type FooComponent = React.FC<IFooProps> & { Bar: React.FC<IBarProps> } const Foo: FooComponent = ({title}) => { return <div>{title}</div> } const Bar: React.FC<IBarProps> = ({content}) => { // 修复原代码中div未闭合的语法错误 return <div>{content}</div> } // 挂载静态子组件,此时无类型报错 Foo.Bar = Bar; export default Foo
方案2:Object.assign 自动推导类型
通过Object.assign合并组件和静态属性,TS会自动推导合并后的完整类型,不需要手动编写交叉类型:
import React from 'react'; interface IFooProps { title: string } interface IBarProps { content: string } const Foo: React.FC<IFooProps> = ({title}) => { return <div>{title}</div> } const Bar: React.FC<IBarProps> = ({content}) => { return <div>{content}</div> } // 合并组件与静态属性,TS自动推导类型 const FinalFoo = Object.assign(Foo, { Bar }) export default FinalFoo
调用效果
两种方案实现后,都可以直接使用你预期的点语法调用组件,TS会正常提供类型校验和代码提示:
import Foo from './Foo' const Content = () => { return ( <> <Foo title="title"/> <Foo.Bar content="content"/> </> ) }
注意事项
- 两种实现都不会丢失原有组件的props类型校验,传参错误时TS会正常抛出提示
- 原示例代码中存在两处语法问题需要修正:Bar组件的末尾div标签未闭合、content属性使用了中文全角引号,实际编写时要替换为英文半角符号
内容的提问来源于stack exchange,提问作者Leroy
相关产品推荐
相关产品推荐

