MichalLytek / MichalLytek/type-graphql

InterfaceType's Class Extensions' Metadata is missing

Open
#1,775 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
8.1k
Forks
672
PR merge metrics
No merged PRs in 30d

Description

**Describe the Bug**
It appears InterfaceTypes do not carry their Class' extensions metadata when queried.

**To Reproduce**
The below repo contains what happens in regular GraphQL.js and what happens in TypeGraphQL. There is more info on the repo's readme.

https://github.com/johnsonjo4531/type-graphql-issue-interface-extensions

**Expected Behavior**
The InterfaceType should carry it's `extensions` metadata when queried

**Logs**
I currently log in the example repo that the tests fail when they do what they shouldn't and pass when they do what they should.

**Environment (please complete the following information):**

- OS: Fedora Linux
- Node 22.11.0
- Package version 2.0.0-rc.2
- TypeScript version 5.7.3

**Additional Context**
Here's the current contents of the repo's readme for better searchability of this issue for others:

# Example Repo Showing Issue with TypeGraphQL's Metadata in Interface Types.

This repo has an example in **src/index.ts** that compares the output of pure graphql.js and type-graphql.
The outputs differ in that the type-graphql does not seem to have the intreface type's extensions metadata along with it this is a bug and prevents me from using
certain libraries along with type-graphql.

## Running the example

If you have `make` available just run the following from the root of the repo:

```bash
make
```

otherwise use the following in your terminal at the root of the repo:

```bash
npm i && npm run build && npm run start
```

Without doing anything you should see the one test failing comparing type-graphql's metadata on the interface to graphql's metadata on the interface.

## More on the Underlying Issue

The following `someMetadata: true` is missing from this **InterfaceType**'s extensions when you try and get the metadata from the query.

**src/User.ts**
```ts
@InterfaceType({
resolveType(obj) {
return obj.$type;
},
})
@Extensions({
someMetadata: true,
})
export class User {
@Field({ nullable: true })
id: number;
}
```

I also have the following query:

**src/QueryRoot.ts**

```ts
@Resolver(() => Query)
export class QueryRoot {
@Query(() => User, {
nullable: true,
})
user(@Info() resolveInfo: GraphQLResolveInfo) {
return {
id: 1,
};
}
}
```

After the schema is built I expect the metadata to be available on the `schema`, just as it is on the `graphQLSchema` (which is the same example schema but in pure graphql.js) but currently it is not in `schema`... and the below test fails instead of passes.

```ts
console.log({
graphqlHasSomeMetadata: (graphQLSchema as any)._queryType._fields.user.type
.extensions.someMetadata,
typeGraphQLHasSomeMetadata: (schema as any)._queryType._fields.user.type
.extensions?.someMetadata,
});
if (
(schema as any)._queryType._fields.user.type.extensions?.someMetadata !=
(graphQLSchema as any)._queryType._fields.user.type.extensions.someMetadata
) {
throw new Error("TEST FAILED: NO SUCH EXTENSION METADATA in TypeGraphQL!!!");
}
console.log("TEST PASSED! Extension metadata exists just as in GraphQL");
```

## The Info I Can Give at the Moment Towards the Problem.

In the below code as I was stepping through it I noticed that `interfaceType.type` does not have the metadata but `interfaceType.metadata` does!
I'm not sure what the difference is between those two, but I thought this information would help.

**type-graphql/build/esm/schema.js**
```ts
// elided...
export class SchemaGenerator {
// elided...
static getGraphQLOutputType(target, propertyName, type, typeOptions = {}) {
let gqlType;
gqlType = convertTypeIfScalar(type);
// elided...
if (!gqlType) {
const interfaceType = this.interfaceTypesInfo.find(it => it.target === type);
if (interfaceType) {
this.usedInterfaceTypes.add(interfaceType.target);
// Around line 509 This interfaceType.type does not have the metadata but interfaceType.metadata does!!!
gqlType = interfaceType.type;
}
}
// elided...
const { nullableByDefault } = BuildContext;
return wrapWithTypeOptions(target, propertyName, gqlType, typeOptions, nullableByDefault);
}
// elided...
}
// elided...
```

Contributor guide

Open the contributing guide

Research direction

Start with the reproduction's src/index.ts, src/User.ts, and src/QueryRoot.ts, then inspect the interface handling in type-graphql/build/esm/schema.js around SchemaGenerator.getGraphQLOutputType. Run make, or npm i && npm run build && npm run start, to compare the GraphQL.js and TypeGraphQL schemas. Done means the interface's extensions metadata is available and the comparison passes.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.