Расширение типов для поддержки вложенных модулей - PullRequest
0 голосов
/ 03 января 2019

Я пытаюсь определить общий интерфейс 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 содержит нужные источники данных, которые я могу создать при необходимости, а также гарантирую, что когда эти источники данных возвращаются в контексте запроса, они будут быть экземплярами источников данных, которые я определил.

Теперь я хочу применить IModule и IContext к другому модулю, который мы назовем Foo. Foo имеет ту же структуру, что и News, но будет экспортировать свои собственные источники данных.

Как я могу изменить эти типы для поддержки более чем одного модуля, где источники данных будут вложены в каждый отдельный модуль?

EDIT:

Мне удалось обновить 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 голосов
/ 03 января 2019

Если я правильно понял, вам просто нужен сопоставленный тип, который объединит все источники данных в объединенный тип. Если это так, то что-то вроде этого должно работать:

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