如何优雅封装类构造函数?Angular Dialog类型安全实现咨询
类型安全的Angular Dialog初始化器优化方案
问题背景
我正在编写原型代码,目标是实现一个能优雅创建Angular Dialog的初始化器,使其可以类型安全地接收构造函数及其参数。当前实现能正常运行,但存在两个问题:
- 难以维护
- 安全性低于预期
当前代码实现:
class SomeDialogClass { name: string; nachname: string; id: number; constructor(name: string, nachname: string, id: number) { this.name = name; this.nachname = nachname; this.id = id; } } // type Constructor = new (...args: unknown[]) => unknown; // <- 无法正常运行 // type Constructor = new (...args: any[]) => any; // <- 这种写法不够优雅,难道没有"Constructor"工具类型吗? function createDialog<DialogClass extends Constructor>(classConstructor: DialogClass, ...args: ConstructorParameters<DialogClass>): InstanceType<DialogClass> { // 由于Constructor类型中使用了"any",此处所有内容都存在不确定性 return new classConstructor(...args); } const instance = createDialog(SomeDialogClass, "John", "Doe", 7); console.log(instance);
优化实现方案
1. 定义泛型构造工具类型消除any
自定义一个通用的泛型构造函数类型,明确参数和实例的类型关联,避免any导致的类型模糊:
// 通用泛型构造类型,支持任意实例类型和参数列表 type Constructor<T = unknown, Args extends unknown[] = unknown[]> = new (...args: Args) => T; class SomeDialogClass { name: string; nachname: string; id: number; constructor(name: string, nachname: string, id: number) { this.name = name; this.nachname = nachname; this.id = id; } } function createDialog<T, Args extends unknown[]>( classConstructor: Constructor<T, Args>, ...args: Args ): T { return new classConstructor(...args); } // 类型完全安全:参数不匹配会触发TS报错,返回值类型精确对应SomeDialogClass const instance = createDialog(SomeDialogClass, "John", "Doe", 7); console.log(instance);
2. 直接利用TS内置约束简化代码
如果不想自定义Constructor类型,可以直接在泛型约束中使用构造函数签名,结合内置工具类型实现类型安全:
class SomeDialogClass { name: string; nachname: string; id: number; constructor(name: string, nachname: string, id: number) { this.name = name; this.nachname = nachname; this.id = id; } } function createDialog<DialogClass extends new (...args: any[]) => any>( classConstructor: DialogClass, ...args: ConstructorParameters<DialogClass> ): InstanceType<DialogClass> { return new classConstructor(...args); } // 同样获得完整类型校验:参数类型、数量不匹配时直接报错 const instance = createDialog(SomeDialogClass, "John", "Doe", 7);
3. 适配Angular Dialog实际场景
针对Angular的MatDialog,可以进一步封装,将参数传入Dialog的data属性,同时保留类型安全:
import { MatDialog } from '@angular/material/dialog'; // 通用Angular Dialog创建函数,支持类型安全的参数传递 function createAngularDialog<T, Args extends unknown[]>( dialog: MatDialog, component: new (...args: Args) => T, ...args: Args ): void { dialog.open(component, { data: args }); } // 示例Dialog组件 class UserDialogComponent { constructor( public name: string, public nachname: string, public id: number ) {} } // 在组件中注入MatDialog后调用(参数不匹配会报错) // createAngularDialog(matDialog, UserDialogComponent, "John", "Doe", 7);
方案优势
- 强类型安全:参数类型、数量不匹配时TypeScript直接报错,返回值类型精确对应目标类,消除
any带来的不确定性 - 易维护性:泛型约束逻辑清晰,后续新增Dialog类无需修改初始化器代码
- 简洁优雅:利用TS内置工具类型或自定义通用类型,避免冗余代码
内容的提问来源于stack exchange,提问作者NoBullsh1t
相关产品推荐
相关产品推荐

