如何从合并后的TypeScript接口获取类实例?
问题解决思路与方案
你遇到的核心问题是:TypeScript的声明合并仅作用于编译时类型系统,mysql2返回的RowDataPacket对象是运行时的普通JS对象,并没有挂载类A的原型方法,所以直接调用helloWorld()会因找不到方法报错。
不用逐个手动赋值属性,有几种更高效的转换方式:
1. 构造函数批量赋值(推荐)
给类A添加接收RowDataPacket对象的构造函数,用Object.assign()批量拷贝属性,避免逐个手动赋值:
import { RowDataPacket } from 'mysql2'; // 声明合并:接口A继承RowDataPacket,定义数据结构 interface A extends RowDataPacket { id: number; name: string; } // 同名类A实现方法 class A { id: number; name: string; constructor(row: RowDataPacket) { // 批量拷贝数据库返回对象的所有属性到当前实例 Object.assign(this, row); } helloWorld() { return `Hello, ${this.name}!`; } } // 使用示例 const [rows] = await connection.execute<A[]>(`SELECT id, name FROM users WHERE id = ?`, [1]); // 将普通对象转换为类A的实例 const userInstance = new A(rows[0]); console.log(userInstance.helloWorld()); // 正常执行
2. 工厂函数封装转换
如果不想修改类的构造函数,可以单独写一个工厂函数处理转换:
function toAInstance(row: RowDataPacket): A { const instance = new A(); Object.assign(instance, row); return instance; } // 使用 const userInstance = toAInstance(rows[0]);
3. 原型挂载(不推荐)
如果想让所有数据库返回的对象都能调用helloWorld(),可以把方法挂载到RowDataPacket的原型上,但会污染全局原型,仅适合全局通用的方法:
// 扩展RowDataPacket的类型 declare module 'mysql2' { interface RowDataPacket { helloWorld(): string; } } // 挂载原型方法 RowDataPacket.prototype.helloWorld = function() { return `Hello, ${this.name}!`; }; // 直接调用 console.log(rows[0].helloWorld()); // 无需转换,直接调用
核心原因说明
TS的声明合并只是让类型系统认为A同时具备接口的结构和类的方法,但运行时类的方法是挂载在原型链上的。mysql2返回的普通对象原型链指向RowDataPacket或Object,并没有类A的原型方法,所以必须通过上述方式把普通对象的属性转移到类实例,或者给目标原型挂载方法,才能在运行时找到helloWorld()。
内容的提问来源于stack exchange,提问作者user
相关产品推荐
相关产品推荐

