TypeScript中使用Partial类型定义defaultProps时出现类型报错
问题复现
- 向
TabsProvider传入orientation配置项,可选值为horizontal、vertical,该属性设为可选,用户不需要强制传入 - 尝试通过定义
defaultProps对象合并的方式,实现和函数参数默认值语法{orientation = 'horizontal'}一致的默认值效果,但逻辑未按预期生效 - TypeScript编译抛出类型错误,提示
orientation属性值可能为undefined
对应复现代码:
export interface TabsProps extends Props { active: string; color?: DanaColor; orientation?: 'horizontal' | 'vertical'; onTabChange: (tabKey: string) => void; children: ReactElement | ReactElement[]; } const defaultProps: Partial<TabsProps> = { orientation: 'horizontal', }; export const Tabs = (props: TabsProps) => { const { children, ...context } = { ...defaultProps, ...props }; return ( <TabsProvider value={context}> <div css={tabs(context.orientation)}> <div css={tabList(context.orientation)} role="tablist"> {children} </div> </div> </TabsProvider> ); };
报错原因
TypeScript不会对Partial<T>类型的对象展开合并做深度类型收窄。当你把defaultProps标注为Partial<TabsProps>类型时,TS会认为这个对象里的所有属性都是可选的,哪怕你实际给orientation赋了固定值,类型层面依然无法判定合并后的context.orientation一定存在,因此会抛出可能为undefined的类型错误。
解决方案
方案1:解构props时直接设置默认值(推荐)
这是React函数组件设置默认值的标准写法,TS可以自动完成类型推导,不需要额外的类型声明,也不会出现类型不识别的问题:
export interface TabsProps extends Props { active: string; color?: DanaColor; orientation?: 'horizontal' | 'vertical'; onTabChange: (tabKey: string) => void; children: ReactElement | ReactElement[]; } export const Tabs = (props: TabsProps) => { // 解构时直接给orientation设置默认值,TS会自动推导其类型为非undefined const { children, orientation = 'horizontal', ...restContext } = props; const context = { ...restContext, orientation }; return ( <TabsProvider value={context}> <div css={tabs(context.orientation)}> <div css={tabList(context.orientation)} role="tablist"> {children} </div> </div> </TabsProvider> ); };
方案2:调整defaultProps的类型声明
如果需要保留统一管理默认值的写法,不要给defaultProps标注Partial<TabsProps>类型,让TS自动推导默认值对象的实际类型,合并后即可识别到orientation为必填属性:
export interface TabsProps extends Props { active: string; color?: DanaColor; orientation?: 'horizontal' | 'vertical'; onTabChange: (tabKey: string) => void; children: ReactElement | ReactElement[]; } // 移除Partial类型标注,用as const固定字面量类型 const defaultProps = { orientation: 'horizontal' as const, }; export const Tabs = (props: TabsProps) => { const mergedProps = { ...defaultProps, ...props }; const { children, ...context } = mergedProps; return ( <TabsProvider value={context}> <div css={tabs(context.orientation)}> <div css={tabList(context.orientation)} role="tablist"> {children} </div> </div> </TabsProvider> ); };
React 18及以上版本已不推荐对函数组件使用
defaultProps属性声明默认值,优先选择解构赋值默认值的写法,类型支持更稳定,代码可读性更高。
内容的提问来源于stack exchange,提问作者Alvaro Losada
相关产品推荐
相关产品推荐

