扩展类型以支持嵌套模块

时间:2019-01-03 02:25:58

标签: typescript apollo-server

我正在尝试定义一个通用的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具有相同的结构,但是将导出其自己的DataSources。

我如何修改这些类型以支持多个模块,而数据源将嵌套在每个模块下?

编辑:

我能够通过传递通用类型来更新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
}

在维护每个数据源上的类型时。映射本身不必担心,它会从较大的模块对象中提取每个数据源的类型,以创建所有数据源的联合类型。

1 个答案:

答案 0 :(得分:0)

如果我正确理解,您只需要将所有数据源聚合为联合类型的映射类型。如果是这样,那么应该可以执行以下操作:

// 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