如何编写NgbModal自定义类型声明以正确推断modalInstance类型?
解决NgbModal组件实例类型推断失效问题
问题背景
需要为NgbModal编写自定义类型声明,让其open方法能正确推断模态框实例的类型。原@ng-bootstrap库的类型定义中,NgbModal.open的content参数和NgbModalRef.componentInstance的返回值均为any:
// @ng-bootstrap/ng-bootstrap/modal/modal.d.ts export declare class NgbModal { open(content: any, options?: NgbModalOptions): NgbModalRef; }
// @ng-bootstrap/ng-bootstrap/modal/modal-ref.d.ts export declare class NgbModalRef { get componentInstance(): any; }
尝试编写types.d.ts扩展原类型:
import { NgbModal as _NgbModal, NgbModalOptions, NgbModalRef as _NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; declare module '@ng-bootstrap/ng-bootstrap' { export interface NgbModal extends _NgbModal { open<T>(content: T, options?: NgbModalOptions): NgbModalRef<T>; } export interface NgbModalRef<T> extends _NgbModalRef { get componentInstance(): InstanceType<T>; } }
模态框组件代码:
export type ModalOption = { title: string; buttonText: string; }; @Component({ selector: 'app-modal', templateUrl: './modal.component.html', styleUrls: ['./modal.component.scss'] }) export class ModalComponent { @Input() data: ModalOption = {} as ModalOption; }
使用场景:
const changeConfirmationModal = modalService.open(ModalComponent, { centered: true }); // 期望这里能正确推断data的类型,但导入扩展后componentInstance变回any changeConfirmationModal.componentInstance.data = { title: 'Some Title', buttonText: 'Some Button Text' };
遇到的问题:
- 不导入扩展类型时,
componentInstance.data类型推断正常,但项目中无法找到@ng-bootstrap的其他导出成员 - 导入扩展类型后,类型推断失效,
componentInstance变回any类型
问题原因
- 扩展类型时导入原
NgbModal和NgbModalRef并继承的方式,破坏了TypeScript的模块合并逻辑,导致泛型方法无法与原方法正确合并 - 泛型参数
T未添加约束,TypeScript无法正确推断content为Angular组件构造函数类型,进而无法正确解析InstanceType<T>
解决方案
修改types.d.ts,移除对原类型的导入,直接利用模块合并特性,并为泛型参数添加Angular组件类型约束:
import { Type } from '@angular/core'; import { NgbModalOptions } from '@ng-bootstrap/ng-bootstrap'; declare module '@ng-bootstrap/ng-bootstrap' { export interface NgbModal { // 约束T为Angular组件构造函数类型 open<T extends Type<any>>(content: T, options?: NgbModalOptions): NgbModalRef<T>; } export interface NgbModalRef<T extends Type<any>> { // 直接返回T的实例类型 get componentInstance(): InstanceType<T>; } }
关键说明
- 不需要继承原
_NgbModal和_NgbModalRef,TypeScript会自动合并模块内的同名接口 - 通过
T extends Type<any>约束泛型参数为Angular组件的构造函数类型,确保TypeScript能正确推断实例类型 - 确保
types.d.ts被TypeScript编译器识别:可将其放在src目录下,或在tsconfig.json的include数组中添加该文件路径
修改后,使用场景中的changeConfirmationModal.componentInstance.data会正确推断为ModalOption类型,同时项目能正常访问@ng-bootstrap的其他导出成员。
内容的提问来源于stack exchange,提问作者Finley Williamson V
相关产品推荐
相关产品推荐

