【问题标题】:Typescript generic type in class constructor's argument类构造函数参数中的打字稿泛型类型
【发布时间】:2019-07-05 08:18:34
【问题描述】:

我正在尝试使用 facebook 数据加载器实现存储库通用模式。

此代码用于 GraphQL API。

抽象基类,我得到错误了吗:

import { Collection, Db, InsertOneWriteOpResult, ObjectId } from "mongodb";
import { RepositoryGeneric } from "../../types/database";

export default abstract class BaseRepository<TEntity, TLoaders> implements RepositoryGeneric<TEntity> {
    protected mongoCollection: Collection<TEntity>;
    protected dataLoaders: TLoaders;

    public constructor(database: Db, collection: string, loaders: TLoaders) {
        this.mongoCollection = database.collection(collection);
        this.dataLoaders = loaders;
    }

    public async findOne(id: ObjectId | string): Promise<TEntity | null> {
        if (typeof id === "string") {
            id = ObjectId.createFromHexString(id);
        }

        // This line is producing the error
        return this.dataLoaders.id.load(id);
    }

    public async create(entity: TEntity): Promise<TEntity> {
        const result: InsertOneWriteOpResult = await this.mongoCollection.insertOne(entity);

        if (!result.result.ok) {
            throw new Error();
        }

        return result.ops[0];
    }
}

类扩展抽象基类:

import { MongoClient } from "mongodb";
import { EntityBusiness } from "../../types/database";
import BusinessLoaders from "../loaders/businessLoaders";
import BaseRepository from "./baseRepository";

export default class BusinessRepository extends BaseRepository<EntityBusiness, BusinessLoaders> {
    public constructor(mongoClient: MongoClient, businessLoaders: BusinessLoaders) {
        super(mongoClient.db(), "business", businessLoaders);

        // tslint:disable-next-line: no-console
        console.log(businessLoaders.id);
    }
}

实现数据加载器的类:

import DataLoader from "dataloader";
import { AggregationCursor, Collection, MongoClient, ObjectId } from "mongodb";
import { EntityBusiness, LoaderCommon } from "../../types/database";

export default class BusinessLoaders implements LoaderCommon<EntityBusiness> {
    private idLoader: DataLoader<ObjectId, EntityBusiness>;

    public constructor(mongoClient: MongoClient) {
        this.idLoader = new DataLoader((keys) => this.idBatch(mongoClient, keys), {
            cacheKeyFn: (key) => key.toHexString(),
        });
    }

    public get id(): DataLoader<ObjectId, EntityBusiness> {
        return this.idLoader;
    }

    private async idBatch(mongoClient: MongoClient, keys: ObjectId[]): Promise<EntityBusiness[]> {
        const collection: Collection<EntityBusiness> = mongoClient.db().collection("business");
        const aggregation: AggregationCursor<EntityBusiness> = collection.aggregate([
            { $match: { _id: { $in: keys } } },
            { $addFields: { __order: { $indexOfArray: [keys, "$_id"] } } },
            { $sort: { __order: 1 } },
            { $project: { __order: 0 } },
        ]);

        return aggregation.toArray();

    }
}

我对打字稿没有太多经验,但我希望不会出错。相反,我得到错误:

错误 TS2339:“TLoaders”类型上不存在属性“id”。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您需要指定泛型类型有一些约束,特别是它有一个id 属性。您可以使用泛型类型定义中的 extends 关键字来做到这一点:

    interface ILoadersInterface<TEntity> {
      id: DataLoader<ObjectId, TEntity | null>
    }
    
    export default abstract class BaseRepository<TEntity, TLoaders extends ILoadersInterface<TEntity>> 
      implements RepositoryGeneric<TEntity> {
        // ...
    }
    

    更一般地说,一个类需要在其内部有足够的类型信息才能正确解析所有代码使用,因为在这种情况下,TypeScript 无法通过使用推断TLoaders 将具有id 属性。从概念上讲,你可以想象一个泛型类型参数大致是unknown,除非你指定了一个约束,比如extends Interfaceextends string等等。

    【讨论】:

    • 谢谢,工作正常。但那不是直接使用接口更好吗? export default abstract class BaseRepository&lt;TEntity&gt; implements RepositoryGeneric&lt;TEntity&gt; { protected dataLoaders: ILoadersInterface&lt;TEntity&gt;; public constructor(database: Db, collection: string, loaders: ILoadersInterface&lt;TEntity&gt;) { // ... } }
    • 这也有效。如果您想更改某些东西的返回值,通用的extends 可能更有用,这样您就可以让它从其中一种方法返回TLoaders,并且该返回值将返回替换为@987654332 的完整类型@ 并从ILoadersInterface 中提取id 属性以及可能定义的任何其他属性。
    猜你喜欢
    • 2017-01-29
    • 2018-05-02
    • 2020-03-22
    • 1970-01-01
    • 2022-11-11
    • 2021-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多