You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TypeScript编写可复用的数据库Wrapper适配旧数据库?

问题描述

接手了无法重构的劣质数据库,需要用TypeScript编写中间层Wrapper,实现GetObjectWithID、Delete等基础操作。已为各数据库对象创建Interface并存储于interfaces.ts,希望通过Wrapper避免大量复制粘贴代码。

需求要点:

  • 用静态类实现Wrapper,无需实例化,仅用于封装对应实体的数据库调用
  • 静态实体类(如User)的方法要返回对应Interface类型的对象
  • 复杂场景下需要转换数据库返回的原始对象,使其适配定义好的接口

当前错误示例代码:

import UserInterface from 'interfaces.ts';
import db from 'the_database';

class DatabaseObject {
  private static objectClass: string;
  private constructor() {}

  static getObject(id: string): object {
    return db.fetch(this.objectClass, id)
  }
}

class User extends DatabaseObject {
  private static objectClass = User;
  
  getObject(id: string): UserInterface {
    return super.getObject(id); // 此处明显错误
  }
}

期望的调用方式:

import UserInterface from 'interfaces.ts';
import User from 'db_wrapper.ts';

const myUserId: string = "abcd1234";
const myUser: UserInterface = User.getObject(myUserId);

console.log(myUser.username);
console.log(myUser.email);
解决方案

可以通过泛型基类实现复用逻辑,同时让子类指定对应的接口类型和数据库标识,具体实现如下:

1. 基类实现(封装通用逻辑)

import db from 'the_database';

// 泛型基类,T代表当前实体对应的接口类型
abstract class DatabaseObject<T> {
  // 子类需重写该静态属性,指定数据库中对应的对象标识(如表名/类名)
  protected static objectKey: string;
  // 私有构造函数,禁止实例化
  private constructor() {}

  // 通用的获取对象方法,返回指定接口类型T
  static getObject<T>(this: typeof DatabaseObject<T>, id: string): T {
    // 调用数据库获取原始数据
    const rawData = db.fetch(this.objectKey, id);
    // 调用子类的转换方法,将原始数据转为接口类型对象
    return this.transform(rawData);
  }

  // 抽象转换方法,子类必须实现,用于适配数据库原始数据到接口
  protected static abstract transform<T>(rawData: unknown): T;
}

2. 子类实现(User实体)

import { DatabaseObject } from './DatabaseObject';
import { UserInterface } from './interfaces';

class User extends DatabaseObject<UserInterface> {
  // 指定数据库中User对应的标识
  protected static objectKey = 'User';

  // 实现转换逻辑,适配数据库返回的原始数据到UserInterface
  protected static transform(rawData: unknown): UserInterface {
    // 这里根据实际数据库返回结构做转换,比如字段映射、类型转换
    const raw = rawData as Record<string, unknown>;
    return {
      id: raw.id as string,
      username: raw.user_name as string, // 假设数据库字段是user_name,接口是username
      email: raw.email as string,
      // 其他字段的转换逻辑
    };
  }
}

3. 调用验证

此时可以按照期望的方式调用,TypeScript会自动推导返回类型为UserInterface:

import { User } from './db_wrapper';

const myUserId = "abcd1234";
const myUser = User.getObject(myUserId); // 类型自动推导为UserInterface

console.log(myUser.username);
console.log(myUser.email);

关键说明

  • 泛型T确保基类方法能返回子类指定的接口类型,避免类型断言
  • objectKey静态属性由子类指定,替代原错误示例中直接赋值类的逻辑
  • transform抽象方法强制子类实现数据转换逻辑,适配劣质数据库的字段差异
  • 基类的getObject方法通过this: typeof DatabaseObject<T>约束静态方法的this类型,确保子类调用时能正确关联泛型参数

内容的提问来源于stack exchange,提问作者Graytr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:30:15