扩展DialogProps时AppModalProps接口出现类型不兼容错误
问题场景
基于@mui/material的Dialog封装自定义弹窗组件,代码如下:
import { Dialog, DialogActions, DialogContent, DialogContentProps, DialogProps, } from '@mui/material' export interface AppModalProps extends DialogProps { header?: JSX.Element content?: JSX.Element actions?: JSX.Element } function AppModal(props: AppModalProps) { const { header, content, actions, } = props return ( <Dialog keepMounted={false} > <DialogContent style={{ padding: '20px 22px', overflow: 'visible', }} > {content} </DialogContent> <DialogActions classes={{ root: 'justify-start pb-0 pl-0 pr-0' }}> {actions} </DialogActions> </Dialog> ) }
运行后触发TypeScript错误:
Interface 'AppModalProps' incorrectly extends interface 'DialogProps'.
Types of property 'content' are incompatible.
Type 'Element | undefined' is not assignable to type 'string | undefined'.
Type 'Element' is not assignable to type 'string'.
尝试将content类型改为React.ReactNode:
export interface AppModalProps extends DialogProps { header?: JSX.Element content?: React.ReactNode actions?: JSX.Element }
仍报错:
Type 'null' is not assignable to type 'string | undefined'
使用版本:
- @mui/material: ^5.14.18
- typescript: ^4.8.4
- node: 18.18.2
疑问:将content作为DialogContent的子元素传入,为何会出现类型不兼容错误?
错误原因
核心是命名冲突:MUI的DialogProps接口本身就定义了content属性,它的类型是string | undefined,作用是设置弹窗的ARIA辅助文本(供屏幕阅读器识别),并非用于传递弹窗内容元素。
你自定义的content属性和DialogProps自带的content重名,TypeScript判定你在覆盖该属性,但类型不匹配,因此抛出错误。即使改成React.ReactNode,由于ReactNode包含null类型,和原属性的string | undefined依然不兼容,所以报错持续。
解决方案
将自定义的content属性重命名(比如modalContent),避免与DialogProps的原生属性冲突,同时调整组件内部的使用逻辑:
import { Dialog, DialogActions, DialogContent, DialogProps, } from '@mui/material' import React from 'react' export interface AppModalProps extends DialogProps { header?: JSX.Element modalContent?: React.ReactNode actions?: JSX.Element } function AppModal(props: AppModalProps) { const { header, modalContent, actions, ...dialogProps // 透传Dialog的原生属性 } = props return ( <Dialog {...dialogProps} keepMounted={false} > {header} <DialogContent style={{ padding: '20px 22px', overflow: 'visible', }} > {modalContent} </DialogContent> <DialogActions classes={{ root: 'justify-start pb-0 pl-0 pr-0' }}> {actions} </DialogActions> </Dialog> ) }
另外补充:原代码未透传Dialog的原生属性(如open、onClose等),添加...dialogProps可让自定义组件支持Dialog的所有原生能力,更符合封装逻辑。
内容的提问来源于stack exchange,提问作者spratap124

