为何React组件直接指定children类型报错?与接口定义有何差异?
问题场景
以下通过接口定义Props包含children的组件写法可正常运行:
interface UserSidebarProps { children?: React.ReactNode } function UserSidebar({children}: UserSidebarProps) { return ( <div> {children} </div> ) }
但直接将children作为函数参数指定类型的写法却无法正常工作:
function UserSidebar(children?: React.ReactNode) { return ( <div> {children} </div> ) }
使用该组件时(<UserSidebar>hello world</UserSidebar>),VSCode会抛出错误:
Type '{ children: Element | null; }' is not assignable to type 'IntrinsicAttributes & ReactNode'. Type '{ children: Element | null; }' is missing the following properties from type 'ReactPortal': key, type, props
核心差异解析
这两种写法本质完全不等价,核心问题出在React组件的参数传递逻辑上:
React组件函数的参数始终是单个Props对象
用JSX语法调用组件时,React会把所有传入的属性(包括children)打包成一个对象传递给组件函数,比如<UserSidebar>hello world</UserSidebar>实际传递的是{ children: "hello world" }这个对象。
第一种写法通过解构赋值从Props对象中提取children属性,完全符合React的参数传递规范;而第二种写法错误地将组件函数的参数定义为单个React.ReactNode类型,相当于要求传入一个React节点,但实际接收的是包含children的对象,类型自然不匹配。类型校验逻辑完全不同
第一种写法用接口定义了Props的结构,TypeScript会校验传入的Props对象是否符合接口约定,和React的组件调用逻辑完全对齐;第二种写法的参数类型是React.ReactNode,但实际传入的是{ children: ReactNode }类型的普通对象,这个对象和ReactNode类型(包含元素、字符串、数字、Portal等)没有兼容关系,因此TypeScript会抛出类型不兼容的错误。扩展性天差地别
第一种写法的接口可以轻松添加其他Props属性(比如className、isOpen等),是React组件的标准写法,扩展性极强;第二种写法如果要新增其他Props,根本无法处理,因为参数只能接收单个值,无法承载多属性的Props对象。
内容的提问来源于stack exchange,提问作者sev

