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;
}
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
add a comment |
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
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
add a comment |
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
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
typescript apollo-server
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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