Extending types to support nested modules





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















I am trying to define a generic Typescript interface that will enforce a pattern on exports from a series of modules. Each module will export pieces of an Apollo GraphQL server that can be stitched together to aid in scalability.



For example let's say that I have a folder called News that has the following structure:



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


In index.ts for News I have defined the following:



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
};


This is behaving exactly as I want it to and it allows me to ensure that the exported News object contains the right DataSources that I can instantiate when needed as well as ensuring that when those DataSources come back on the request context that they will be instances of the DataSources I have defined.



What I want to do next is be able to apply IModule and IContext to another module we'll call Foo. Foo has the same structure as News but will export its own DataSources.



How can I modify these types to support more than a single module where DataSources will be nested under each individual module?



EDIT:



I was able to update IModule by passing in a generic type:



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

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


And that seems to be working fine.



In general I'm looking to take an object that looks like this:



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


And turn it into this:



{
DataSourceA,
DataSourceB,
DataSourceC,
DataSourceD
}


While maintaining the types on each DataSource. The mapping itself is not a concern its distilling the type of each DataSource from the larger module object to create a union type of all of the DataSources.










share|improve this question

























  • Could you please clarify what would the end interface that combines multiple DataSources should look like? Can be totally invalid TypeScript, but might help to get the idea of what you are trying to achieve.

    – Grassator
    Jan 3 at 11:22











  • @Grassator - I've provided more details above.

    – adampetrie
    Jan 3 at 14:27


















0















I am trying to define a generic Typescript interface that will enforce a pattern on exports from a series of modules. Each module will export pieces of an Apollo GraphQL server that can be stitched together to aid in scalability.



For example let's say that I have a folder called News that has the following structure:



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


In index.ts for News I have defined the following:



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
};


This is behaving exactly as I want it to and it allows me to ensure that the exported News object contains the right DataSources that I can instantiate when needed as well as ensuring that when those DataSources come back on the request context that they will be instances of the DataSources I have defined.



What I want to do next is be able to apply IModule and IContext to another module we'll call Foo. Foo has the same structure as News but will export its own DataSources.



How can I modify these types to support more than a single module where DataSources will be nested under each individual module?



EDIT:



I was able to update IModule by passing in a generic type:



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

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


And that seems to be working fine.



In general I'm looking to take an object that looks like this:



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


And turn it into this:



{
DataSourceA,
DataSourceB,
DataSourceC,
DataSourceD
}


While maintaining the types on each DataSource. The mapping itself is not a concern its distilling the type of each DataSource from the larger module object to create a union type of all of the DataSources.










share|improve this question

























  • Could you please clarify what would the end interface that combines multiple DataSources should look like? Can be totally invalid TypeScript, but might help to get the idea of what you are trying to achieve.

    – Grassator
    Jan 3 at 11:22











  • @Grassator - I've provided more details above.

    – adampetrie
    Jan 3 at 14:27














0












0








0








I am trying to define a generic Typescript interface that will enforce a pattern on exports from a series of modules. Each module will export pieces of an Apollo GraphQL server that can be stitched together to aid in scalability.



For example let's say that I have a folder called News that has the following structure:



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


In index.ts for News I have defined the following:



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
};


This is behaving exactly as I want it to and it allows me to ensure that the exported News object contains the right DataSources that I can instantiate when needed as well as ensuring that when those DataSources come back on the request context that they will be instances of the DataSources I have defined.



What I want to do next is be able to apply IModule and IContext to another module we'll call Foo. Foo has the same structure as News but will export its own DataSources.



How can I modify these types to support more than a single module where DataSources will be nested under each individual module?



EDIT:



I was able to update IModule by passing in a generic type:



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

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


And that seems to be working fine.



In general I'm looking to take an object that looks like this:



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


And turn it into this:



{
DataSourceA,
DataSourceB,
DataSourceC,
DataSourceD
}


While maintaining the types on each DataSource. The mapping itself is not a concern its distilling the type of each DataSource from the larger module object to create a union type of all of the DataSources.










share|improve this question
















I am trying to define a generic Typescript interface that will enforce a pattern on exports from a series of modules. Each module will export pieces of an Apollo GraphQL server that can be stitched together to aid in scalability.



For example let's say that I have a folder called News that has the following structure:



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


In index.ts for News I have defined the following:



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
};


This is behaving exactly as I want it to and it allows me to ensure that the exported News object contains the right DataSources that I can instantiate when needed as well as ensuring that when those DataSources come back on the request context that they will be instances of the DataSources I have defined.



What I want to do next is be able to apply IModule and IContext to another module we'll call Foo. Foo has the same structure as News but will export its own DataSources.



How can I modify these types to support more than a single module where DataSources will be nested under each individual module?



EDIT:



I was able to update IModule by passing in a generic type:



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

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


And that seems to be working fine.



In general I'm looking to take an object that looks like this:



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


And turn it into this:



{
DataSourceA,
DataSourceB,
DataSourceC,
DataSourceD
}


While maintaining the types on each DataSource. The mapping itself is not a concern its distilling the type of each DataSource from the larger module object to create a union type of all of the DataSources.







typescript apollo-server






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 3 at 14:26







adampetrie

















asked Jan 3 at 2:25









adampetrieadampetrie

455519




455519













  • Could you please clarify what would the end interface that combines multiple DataSources should look like? Can be totally invalid TypeScript, but might help to get the idea of what you are trying to achieve.

    – Grassator
    Jan 3 at 11:22











  • @Grassator - I've provided more details above.

    – adampetrie
    Jan 3 at 14:27



















  • Could you please clarify what would the end interface that combines multiple DataSources should look like? Can be totally invalid TypeScript, but might help to get the idea of what you are trying to achieve.

    – Grassator
    Jan 3 at 11:22











  • @Grassator - I've provided more details above.

    – adampetrie
    Jan 3 at 14:27

















Could you please clarify what would the end interface that combines multiple DataSources should look like? Can be totally invalid TypeScript, but might help to get the idea of what you are trying to achieve.

– Grassator
Jan 3 at 11:22





Could you please clarify what would the end interface that combines multiple DataSources should look like? Can be totally invalid TypeScript, but might help to get the idea of what you are trying to achieve.

– Grassator
Jan 3 at 11:22













@Grassator - I've provided more details above.

– adampetrie
Jan 3 at 14:27





@Grassator - I've provided more details above.

– adampetrie
Jan 3 at 14:27












1 Answer
1






active

oldest

votes


















0














If I understood correctly you just need a mapped type that would aggregate all data sources into a union type. If that is the case then something like this should work:



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





share|improve this answer
























  • I think that this is the right approach however AllDataSources would actually contain an instance of each DataSource whereas in the modules they are typeof DataSource. Can you update your answer to reflect that? I've been trying to and struggling. Additionally, can you elaborate on the definition of AllDataSources to help me understand what's happening there? Thanks!

    – adampetrie
    Jan 4 at 20:01














Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54015576%2fextending-types-to-support-nested-modules%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














If I understood correctly you just need a mapped type that would aggregate all data sources into a union type. If that is the case then something like this should work:



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





share|improve this answer
























  • I think that this is the right approach however AllDataSources would actually contain an instance of each DataSource whereas in the modules they are typeof DataSource. Can you update your answer to reflect that? I've been trying to and struggling. Additionally, can you elaborate on the definition of AllDataSources to help me understand what's happening there? Thanks!

    – adampetrie
    Jan 4 at 20:01


















0














If I understood correctly you just need a mapped type that would aggregate all data sources into a union type. If that is the case then something like this should work:



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





share|improve this answer
























  • I think that this is the right approach however AllDataSources would actually contain an instance of each DataSource whereas in the modules they are typeof DataSource. Can you update your answer to reflect that? I've been trying to and struggling. Additionally, can you elaborate on the definition of AllDataSources to help me understand what's happening there? Thanks!

    – adampetrie
    Jan 4 at 20:01
















0












0








0







If I understood correctly you just need a mapped type that would aggregate all data sources into a union type. If that is the case then something like this should work:



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





share|improve this answer













If I understood correctly you just need a mapped type that would aggregate all data sources into a union type. If that is the case then something like this should work:



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






share|improve this answer












share|improve this answer



share|improve this answer










answered Jan 3 at 16:15









GrassatorGrassator

1,01979




1,01979













  • I think that this is the right approach however AllDataSources would actually contain an instance of each DataSource whereas in the modules they are typeof DataSource. Can you update your answer to reflect that? I've been trying to and struggling. Additionally, can you elaborate on the definition of AllDataSources to help me understand what's happening there? Thanks!

    – adampetrie
    Jan 4 at 20:01





















  • I think that this is the right approach however AllDataSources would actually contain an instance of each DataSource whereas in the modules they are typeof DataSource. Can you update your answer to reflect that? I've been trying to and struggling. Additionally, can you elaborate on the definition of AllDataSources to help me understand what's happening there? Thanks!

    – adampetrie
    Jan 4 at 20:01



















I think that this is the right approach however AllDataSources would actually contain an instance of each DataSource whereas in the modules they are typeof DataSource. Can you update your answer to reflect that? I've been trying to and struggling. Additionally, can you elaborate on the definition of AllDataSources to help me understand what's happening there? Thanks!

– adampetrie
Jan 4 at 20:01







I think that this is the right approach however AllDataSources would actually contain an instance of each DataSource whereas in the modules they are typeof DataSource. Can you update your answer to reflect that? I've been trying to and struggling. Additionally, can you elaborate on the definition of AllDataSources to help me understand what's happening there? Thanks!

– adampetrie
Jan 4 at 20:01






















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54015576%2fextending-types-to-support-nested-modules%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

ts Property 'filter' does not exist on type '{}'

mat-slide-toggle shouldn't change it's state when I click cancel in confirmation window