Angular9扩展MatDialog报错:私有属性_attachDialogContainer重复声明
Angular 8升级到9后CustomDialog继承MatDialog的问题解决方案
问题根源
Angular 9(及配套的Material 9)中,TypeScript类型检查更严格,同时MatDialog的内部私有方法(如_attachDialogContainer、_createInjector)不再允许子类重写。直接继承并声明同名私有方法会触发类型冲突;去掉@Injectable()则会导致依赖注入系统无法正确初始化父类内部依赖,引发运行时错误。
可行解决方案
方案1:用装饰器模式封装MatDialog(推荐)
放弃继承MatDialog,改为将其作为依赖注入到自定义服务中,通过包装方式扩展功能,完全规避私有方法的访问问题。
示例代码:
@Injectable({ providedIn: 'root' }) export class CustomDialog { constructor(private matDialog: MatDialog) {} open<T, D = any, R = any>( componentType: ComponentType<T>, config?: CustomDialogConfig<D> ): MatDialogRef<T, R> { // 在这里注入自定义逻辑,比如覆盖默认配置、添加全局处理 const mergedConfig = { ...new CustomDialogConfig(), ...config, containerComponent: CustomDialogContainer // 指定自定义容器组件(如果需要) }; return this.matDialog.open(componentType, mergedConfig as MatDialogConfig<D>); } // 直接复用MatDialog的原生方法 closeAll(): void { this.matDialog.closeAll(); } getDialogById(id: string): MatDialogRef<any> | undefined { return this.matDialog.getDialogById(id); } }
方案2:自定义对话框容器(针对容器逻辑修改需求)
如果核心需求是自定义对话框的容器渲染逻辑,无需继承MatDialog,只需创建MatDialogContainer的子类,在调用open时指定即可。
- 创建自定义容器组件:
@Component({ selector: 'app-custom-dialog-container', template: ` <div class="custom-dialog-wrapper"> <mat-dialog-title *ngIf="dialogConfig.title">{{ dialogConfig.title }}</mat-dialog-title> <mat-dialog-content class="custom-content"> <ng-template matDialogContent></ng-template> </mat-dialog-content> <mat-dialog-actions align="end" class="custom-actions"> <ng-template matDialogActions></ng-template> </mat-dialog-actions> </div> `, styles: [`.custom-dialog-wrapper { padding: 16px; }`] }) export class CustomDialogContainer extends MatDialogContainer { constructor( overlayRef: OverlayRef, @Inject(MAT_DIALOG_DATA) data: any, dialogConfig: MatDialogConfig, elementRef: ElementRef<HTMLElement>, renderer: Renderer2, @Optional() @Inject(MAT_DIALOG_SCROLL_STRATEGY) scrollStrategy: ScrollStrategy, @Optional() @Inject(MAT_DIALOG_DEFAULT_OPTIONS) defaultOptions: MatDialogConfig ) { super(overlayRef, data, dialogConfig, elementRef, renderer, scrollStrategy, defaultOptions); // 在这里添加容器的自定义逻辑,比如动态修改样式、添加事件监听 } }
- 在CustomDialog服务中关联容器:
@Injectable({ providedIn: 'root' }) export class CustomDialog { constructor(private matDialog: MatDialog) {} open<T>(component: ComponentType<T>, config?: CustomDialogConfig) { return this.matDialog.open(component, { ...config, containerComponent: CustomDialogContainer }); } }
方案3:临时绕过类型检查(不推荐)
如果必须保留原有继承结构,可通过类型断言临时绕过检查,但会破坏类型安全,后续版本升级仍可能出问题:
- 将子类中
_createInjector和_attachDialogContainer的访问修饰符改为/* private */,并添加// @ts-ignore注释 - 在
tsconfig.json中针对当前文件关闭strictPropertyInitialization(不推荐全局关闭)
但强烈建议优先使用前两种方案,避免依赖框架私有API。
内容的提问来源于stack exchange,提问作者Mazhar Ali
相关产品推荐
相关产品推荐

