TypeScript中如何传递实现DataAdapterInterface的类而非实例?
我定义了如下接口:
interface DataAdapterInterface { init(url: string): void execute(command: string, values?: string[]): Promise<any> insert(items: any[]): Promise<any> find(items: any[]): Promise<any> update(items: any[]): Promise<boolean> remove(items: any[]): Promise<boolean> }
还有一个装饰器函数:
export function protocol(protocol: string) { return function (constructor: Function) { constructor['__protocol'] = protocol; }; }
接着创建了实现该接口的类:
@protocol("mysql") export class MySQLAdapter implements DataAdapterInterface { init(url: string): void {} execute(command: string): Promise<any> {} insert(item: any[]): Promise<any> {} find(item: any[]): Promise<any> {} update(item: any[]): Promise<boolean> {} remove(item: any[]): Promise<boolean> {} }
另外有一个注册函数:
export function register(adapter: DataAdapterInterface) { ConnectionFactory.register(adapter['__protocol'], adapter) }
执行register(MySQLAdapter);时,TypeScript报错提示MySQLAdapter不是DataAdapterInterface类型。JavaScript运行正常,把参数改成any能消除编译错误,但我希望限制参数仅为实现DataAdapterInterface的类,请问有没有无需实例化类也不用any类型的传递方式?
问题核心是:你传入的是类的构造函数,但register的参数类型定义的是接口的实例类型,TypeScript的类型检查自然不通过。只需调整参数类型为对应接口的构造函数类型即可解决。
1. 定义构造函数类型
先声明一个类型,代表能创建DataAdapterInterface实例的构造函数:
type DataAdapterConstructor = new () => DataAdapterInterface;
2. 优化装饰器类型(可选,提升严谨性)
把原装饰器中宽泛的Function类型替换为上面的构造函数类型,让类型检查更严格:
export function protocol(protocol: string) { return function (constructor: DataAdapterConstructor) { constructor['__protocol'] = protocol; }; }
3. 修改register函数的参数类型
将register的参数类型从DataAdapterInterface改为DataAdapterConstructor,并调整内部逻辑(现在接收的是构造函数而非实例):
export function register(adapterConstructor: DataAdapterConstructor) { ConnectionFactory.register(adapterConstructor['__protocol'], adapterConstructor) }
4. 调用验证
现在执行register(MySQLAdapter);不会再有类型错误,同时TypeScript会自动校验传入的类是否实现了DataAdapterInterface,完全满足“无需实例化、不用any类型”的需求。
额外优化:为构造函数添加协议属性类型
如果想让__protocol属性获得类型提示,可以扩展构造函数类型:
type DataAdapterConstructor = new () => DataAdapterInterface & { __protocol?: string; };
这样访问adapterConstructor['__protocol']时,TypeScript会识别该属性的存在,不会出现类型报错。
内容的提问来源于stack exchange,提问作者Magician

