伪造的数据库缺少 x 属性,但这些属性是私有的

Faked database is missing x properties, however those properties are private

我正在尝试为我的代码编写一些测试。我正在使用依赖注入,我正在尝试创建我的数据库的伪造版本,以便在 运行 测试时使用。

我正在使用关键字 implements 来定义我的伪造数据库,但是由于这个伪造的数据库缺少某些属性,我收到了打字稿错误,但是,这些属性是私有的,并且从未在 class

之外使用

这是一个例子:

class Database {
    private client: MongoClient;

    public async getData(query: string): Promise<{ name: string }> {
        return await this.client.db('db').collection('collection').findOne({ name: query });
    }
}

class MockDatabase implements Database {
    public async getData(query: string): Promise<{ name: string }> {
        return {
            name: 'Jo'
        }
    }
}

function makeApp(database: Database) {
    console.log(`Here's your app`);
}
const fakeDB = new MockDatabase();
const app = makeApp(fakeDB)

Typescript 在声明 MockDatabase 以及在 makeApp 函数中使用它时都会出错。

Property 'client' is missing in type 'MockDatabase' but required in type 'Database'

我应该如何伪造数据库或类似的其他服务?

A Database 需要有 client 属性,因为 属性 是 private,这意味着你只能得到一个有效的 Database 来自 Database 构造函数。没有办法用不同的声明来“模拟”Database,因为 private properties need to come from the same declaration in order to be compatible. This restriction is important, because private properties are not completely inaccessible from outside the object; they are accessible from other instances of the same class. See 需要更多信息。


无论如何,与其尝试模拟 Database,不如考虑创建一个新的 interface,它只是 Database 的“public 部分”。它看起来像这样:

// manually written out
interface IDatabase {
  getData(query: string): Promise<{ name: string }>
}

您可以让编译器为您计算这个,因为 the keyof operator 只有 returns 对象类型的 public 属性 名称:

// computed
interface IDatabase extends Pick<Database, keyof Database> { }

类型 Pick<Database, keyof Database> 使用 the Pick<T, K> utility type 到 select 只是 Database 的 public 属性。在这种情况下,它只是 "getData",因此计算出的 IDatabase 等同于手动计算出的 IDatabase


现在我们将对 Database 的引用更改为 IDatabase 我们只关心 public 部分的任何地方:

class MockDatabase implements IDatabase {
  public async getData(query: string): Promise<{ name: string }> {
    return {
      name: 'Jo'
    }
  }
}

function makeApp(database: IDatabase) {
  console.log(`Here's your app`);
}
const fakeDB = new MockDatabase();
const app = makeApp(fakeDB)

一切都按预期进行。

Playground link to code