React Typescript自定义Tabs组件访问children的props报类型错误如何解决?
报错原因
- 初始
children类型定义不严谨
你将children声明为ReactNode[]类型,而ReactNode是包含字符串、数字、空值、React元素等的联合类型,非React元素类型的节点本身不存在props属性,因此直接访问children[0].props会触发类型错误。 - 加
isValidElement后报unknown的原因
React内置的isValidElement类型守卫默认仅会将值收窄为泛型参数默认是unknown的ReactElement类型,TS无法推断该元素的props上存在label属性,因此访问props.label时会提示对象类型为unknown。
你之前遍历children的代码没有报错,是因为遍历场景下TS的类型收窄粒度更细,同时你没有直接访问可选链后的深层属性,才没有触发报错。
解决方法
方案1:约束children类型(推荐)
先给你的Tab子组件定义固定的Props类型,再约束Tabs的children只能是对应类型的React元素,从根源避免类型问题:
import type { FC, ReactElement, ReactNode } from 'react'; // 先定义Tab子项的Props类型 type TabItemProps = { label: TabLabel; children: ReactNode; } // 对应的Tab子组件示例 export const TabItem: FC<TabItemProps> = ({ children }) => <>{children}</>; // Tabs组件修改children类型 const Tabs: FC<{ // 支持单个或多个TabItem子元素 children: ReactElement<TabItemProps> | ReactElement<TabItemProps>[]; }> = ({ children }) => { // 统一转为数组处理,避免单元素场景报错 const childList = Array.isArray(children) ? children : [children]; const [activeTab, setActiveTab] = useState<TabLabel | null>(null); useEffect(() => { // 此时childList的元素已经是确定类型,不需要额外判断也能正常访问props setActiveTab(childList[0]?.props.label ?? null); }, [childList]); // 遍历的代码也可以直接简化,不需要再做isValidElement判断 return ( <div> {childList.map(child => ( <button className={cn('checkout-tabs_tab', { '-active': child.props.label === activeTab })} key={child.props.label} onClick={() => setActiveTab(child.props.label)} role="tab" type="button" > {child.props.label} </button> ))} </div> ) }
方案2:给isValidElement加泛型约束
如果你不想修改children的原有定义,可以直接给isValidElement传入泛型参数,指定元素的Props类型,完成类型收窄:
useEffect(() => { const firstChild = children[0]; // 传入TabItemProps泛型,告诉TS该元素的props结构 if (isValidElement<TabItemProps>(firstChild)) { setActiveTab(firstChild.props.label); } }, []);
内容的提问来源于stack exchange,提问作者pti4a
相关产品推荐
相关产品推荐

