【问题标题】:Extending types to support nested modules扩展类型以支持嵌套模块
【发布时间】:2019-05-29 15:30:45
【问题描述】:

我正在尝试定义一个通用 Typescript 接口,该接口将对一系列模块的导出强制执行一种模式。每个模块都将导出 Apollo GraphQL 服务器的各个部分,这些部分可以拼接在一起以提高可扩展性。

例如,假设我有一个名为 News 的文件夹,其结构如下:

News
 |_ index.ts
 |_ typeDefs.ts
 |_ resolvers.ts
 |_ dataSources
     |_ index.ts
     |_ SourceA.ts
     |_ SourceB.ts

index.ts 的新闻中,我定义了以下内容:

import { IResolvers } from "apollo-server";
import { DocumentNode } from "graphql";
import * as DataSources from "./datasources";
import resolvers from "./resolvers";
import schema from "./typeDefs";

export interface IContext {
  dataSources: {
    [R in keyof typeof DataSources]: InstanceType<typeof DataSources[R]>
  };
}

interface IModule {
  resolvers: IResolvers;
  schema: DocumentNode;
  dataSources: typeof DataSources;
}

export const News: IModule = {
  resolvers,
  schema,
  dataSources: DataSources
};

这完全符合我的要求,它允许我确保导出的 News 对象包含正确的数据源,我可以在需要时实例化这些数据源,并确保当这些数据源返回请求上下文时,它们将是我定义的数据源的实例。

接下来我想做的是能够将IModuleIContext 应用到另一个我们称为Foo 的模块。 Foo 与 News 具有相同的结构,但会导出自己的 DataSource。

如何修改这些类型以支持多个模块,其中数据源将嵌套在每个单独的模块下?

编辑:

我可以通过传入泛型类型来更新IModule

interface IModule<TDataSources> {
  resolvers: IResolvers;
  schema: DocumentNode;
  dataSources: TDataSources;
}

const News: IModule<typeof DataSources> = {
  resolvers,
  schema,
  dataSources: DataSources
};

这似乎工作正常。

一般来说,我想要一个看起来像这样的对象:

{
  modules: {
    Foo: {
      resolvers,
      schema,
      dataSources: {
        DataSourceA,
        DataSourceB
      },
    },
    Bar: {
      resolvers,
      schema,
      dataSources: {
        DataSourceC,
        DataSourceD
      },
    },
  }
}

然后把它变成这样:

{
  DataSourceA,
  DataSourceB,
  DataSourceC,
  DataSourceD
}

同时维护每个 DataSource 上的类型。映射本身不是问题,它从较大的模块对象中提取每个 DataSource 的类型以创建所有 DataSource 的联合类型。

【问题讨论】:

  • 能否请您澄清一下结合多个数据源的最终接口应该是什么样子?可能是完全无效的 TypeScript,但可能有助于了解您要实现的目标。
  • @Grassator - 我在上面提供了更多详细信息。

标签: typescript apollo-server


【解决方案1】:

如果我理解正确,您只需要一个将所有数据源聚合为联合类型的映射类型。如果是这样的话,那么这样的事情应该可以工作:

// this is just for an example, you would have real data instead
declare const data: {
    modules: {
        Foo: IModule<DataSourceA | DataSourceB>,
        Bar: IModule<DataSourceC | DataSourceD>
    }
}

type AllDataSources<T extends { [K in keyof T]: IModule<any> }> =
    T[keyof T]["dataSources"]

type Result = AllDataSources<typeof data["modules"]> // DataSourceA | DataSourceB | DataSourceC | DataSourceD

【讨论】:

  • 我认为这是正确的方法,但是 AllDataSources 实际上会包含每个 DataSource 的实例,而在模块中它们是 typeof DataSource。您可以更新您的答案以反映这一点吗?我一直在努力和挣扎。此外,您能否详细说明 AllDataSources 的定义,以帮助我了解那里发生了什么?谢谢!
猜你喜欢
  • 2019-12-29
  • 1970-01-01
  • 2020-10-13
  • 2010-12-13
  • 2023-01-10
  • 2020-12-31
  • 1970-01-01
  • 2021-11-15
  • 2016-06-10
相关资源
最近更新 更多