Skip to content

Commit 4e204ba

Browse files
committed
Typed base schema meta
1 parent e3aa56a commit 4e204ba

File tree

2 files changed

+78
-28
lines changed

2 files changed

+78
-28
lines changed

packages/extend/src/extend.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ test("using an existing object type", () => {
419419
`);
420420
});
421421

422-
test("errors when no type ", () => {
422+
test("errors when no type exists with that name", () => {
423423
expect(() => {
424424
extend((base) => ({
425425
query: {
@@ -525,7 +525,9 @@ test(".scalar works for custom scalars", () => {
525525
},
526526
}),
527527
});
528-
const extended = extend((base) => ({
528+
const extended = extend<{
529+
Something: typeof Something;
530+
}>((base) => ({
529531
query: {
530532
hello: g.field({
531533
type: base.scalar("Something"),

packages/extend/src/index.ts

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,24 @@ import {
2626
parse,
2727
ObjectTypeDefinitionNode,
2828
print,
29+
GraphQLInterfaceType,
30+
GraphQLInputObjectType,
31+
GraphQLUnionType,
32+
GraphQLScalarType,
2933
} from "graphql";
3034

3135
import {
3236
GField,
3337
GObjectType,
34-
GArg,
3538
GEnumType,
3639
GUnionType,
3740
GInterfaceType,
3841
GScalarType,
3942
GOutputType,
4043
GInputObjectType,
44+
GInputType,
45+
GArg,
46+
GInterfaceField,
4147
} from "@graphql-ts/schema";
4248

4349
const builtinScalars = new Set(specifiedScalarTypes.map((x) => x.name));
@@ -91,11 +97,11 @@ const builtinScalars = new Set(specifiedScalarTypes.map((x) => x.name));
9197
* }
9298
* ```
9399
*/
94-
export function extend(
100+
export function extend<Types extends Record<string, NamedType>>(
95101
extension:
96102
| Extension
97103
| readonly Extension[]
98-
| ((base: BaseSchemaMeta) => Extension | readonly Extension[])
104+
| ((base: BaseSchemaMeta<Types>) => Extension | readonly Extension[])
99105
): (schema: GraphQLSchema) => GraphQLSchema {
100106
return (schema) => {
101107
const getType = (name: string) => {
@@ -113,76 +119,81 @@ export function extend(
113119
typeof extension === "function"
114120
? extension({
115121
schema,
122+
all(name) {
123+
return getType(name as string) as any;
124+
},
116125
object(name) {
117-
const graphQLType = getType(name);
126+
const graphQLType = getType(name as string);
118127
if (!isObjectType(graphQLType)) {
119128
throw new Error(
120129
`There is a type named ${JSON.stringify(
121130
name
122131
)} in the schema being extended but it is not an object type`
123132
);
124133
}
125-
return graphQLType;
134+
return graphQLType as any;
126135
},
127136
inputObject(name) {
128-
const graphQLType = getType(name);
137+
const graphQLType = getType(name as string);
129138
if (!isInputObjectType(graphQLType)) {
130139
throw new Error(
131140
`There is a type named ${JSON.stringify(
132141
name
133142
)} in the schema being extended but it is not an input object type`
134143
);
135144
}
136-
return graphQLType;
145+
return graphQLType as any;
137146
},
138147
enum(name) {
139-
const graphQLType = getType(name);
148+
const graphQLType = getType(name as string);
140149
if (!isEnumType(graphQLType)) {
141150
throw new Error(
142151
`There is a type named ${JSON.stringify(
143152
name
144153
)} in the schema being extended but it is not an enum type`
145154
);
146155
}
147-
return graphQLType;
156+
return graphQLType as any;
148157
},
149158
interface(name) {
150-
const graphQLType = getType(name);
159+
const graphQLType = getType(name as string);
151160
if (!isInterfaceType(graphQLType)) {
152161
throw new Error(
153162
`There is a type named ${JSON.stringify(
154163
name
155164
)} in the schema being extended but it is not an interface type`
156165
);
157166
}
158-
return graphQLType;
167+
return graphQLType as any;
159168
},
160169
scalar(name) {
161-
if (builtinScalars.has(name)) {
170+
if (builtinScalars.has(name as string)) {
162171
throw new Error(
163-
`The names of built-in scalars cannot be passed to BaseSchemaInfo.scalar but ${name} was passed`
172+
`The names of built-in scalars cannot be passed to BaseSchemaInfo.scalar but ${
173+
name as string
174+
} was passed`
164175
);
165176
}
166-
const graphQLType = getType(name);
177+
const graphQLType = getType(name as string);
167178
if (!isScalarType(graphQLType)) {
168179
throw new Error(
169180
`There is a type named ${JSON.stringify(
170181
name
171182
)} in the schema being extended but it is not a scalar type`
172183
);
173184
}
174-
return graphQLType;
185+
return graphQLType as any;
175186
},
176187
union(name) {
177-
const graphQLType = getType(name);
188+
const graphQLType = getType(name as string);
178189
if (!isUnionType(graphQLType)) {
179190
throw new Error(
180191
`There is a type named ${JSON.stringify(
181192
name
182193
)} in the schema being extended but it is not a union type`
183194
);
184195
}
185-
return graphQLType;
196+
return graphQLType as any;
186197
},
187198
})
188199
: extension
@@ -426,12 +437,39 @@ export type Extension = {
426437
// unreferencedConcreteInterfaceImplementations?: ObjectType<Context, any>[];
427438
};
428439

440+
export type NamedType =
441+
| GObjectType<any, unknown>
442+
| GInputObjectType<{ [key: string]: GArg<GInputType, boolean> }>
443+
| GEnumType<Record<string, unknown>>
444+
| GUnionType<unknown, unknown>
445+
| GInterfaceType<
446+
unknown,
447+
Record<string, GInterfaceField<any, GOutputType<unknown>, unknown>>,
448+
unknown
449+
>
450+
| GScalarType<unknown>;
451+
452+
export type NamedTypes = Record<string & {}, NamedType>;
453+
454+
type TypeOfKind<Types extends Record<string, NamedType>, Constraint> = {
455+
[K in keyof Types]: Extract<Types[K], Constraint> extends never ? never : K;
456+
}[keyof Types];
457+
429458
/**
430459
* This object contains the schema being extended and functions to get GraphQL
431460
* types from the schema.
432461
*/
433-
export type BaseSchemaMeta = {
462+
export type BaseSchemaMeta<
463+
Types extends Record<string, NamedType> = NamedTypes,
464+
> = {
434465
schema: GraphQLSchema;
466+
all<
467+
Name extends {
468+
[K in keyof Types]: string extends K ? never : K;
469+
}[keyof Types],
470+
>(
471+
name: Name
472+
): Types[Name];
435473
/**
436474
* Gets an {@link GObjectType object type} from the existing GraphQL schema. If
437475
* there is no object type in the existing schema with the name passed, an
@@ -452,7 +490,9 @@ export type BaseSchemaMeta = {
452490
* }))(originalSchema);
453491
* ```
454492
*/
455-
object(name: string): GObjectType<unknown, unknown>;
493+
object<Name extends TypeOfKind<Types, GraphQLObjectType>>(
494+
name: Name
495+
): Extract<Types[Name], GraphQLObjectType>;
456496
/**
457497
* Gets an {@link GInputObjectType input object type} from the existing GraphQL
458498
* schema. If there is no input object type in the existing schema with the
@@ -479,9 +519,9 @@ export type BaseSchemaMeta = {
479519
* }))(originalSchema);
480520
* ```
481521
*/
482-
inputObject(
483-
name: string
484-
): GInputObjectType<{ [key: string]: GArg<any, boolean> }, boolean>;
522+
inputObject<Name extends TypeOfKind<Types, GraphQLInputObjectType>>(
523+
name: Name
524+
): Extract<Types[Name], GraphQLInputObjectType>;
485525
/**
486526
* Gets an {@link GEnumType enum type} from the existing GraphQL schema. If
487527
* there is no enum type in the existing schema with the name passed, an error
@@ -507,7 +547,9 @@ export type BaseSchemaMeta = {
507547
* }))(originalSchema);
508548
* ```
509549
*/
510-
enum(name: string): GEnumType<Record<string, unknown>>;
550+
enum<Name extends TypeOfKind<Types, GEnumType<any>>>(
551+
name: Name
552+
): Extract<Types[Name], GEnumType<any>>;
511553
/**
512554
* Gets a {@link GUnionType union type} from the existing GraphQL schema. If
513555
* there is no union type in the existing schema with the name passed, an
@@ -528,7 +570,9 @@ export type BaseSchemaMeta = {
528570
* }))(originalSchema);
529571
* ```
530572
*/
531-
union(name: string): GUnionType<unknown, unknown>;
573+
union<Name extends TypeOfKind<Types, GraphQLUnionType>>(
574+
name: Name
575+
): Extract<Types[Name], GraphQLUnionType>;
532576
/**
533577
* Gets an {@link GInterfaceType interface type} from the existing GraphQL
534578
* schema. If there is no interface type in the existing schema with the name
@@ -549,7 +593,9 @@ export type BaseSchemaMeta = {
549593
* }))(originalSchema);
550594
* ```
551595
*/
552-
interface(name: string): GInterfaceType<unknown, any, unknown>;
596+
interface<Name extends TypeOfKind<Types, GraphQLInterfaceType>>(
597+
name: Name
598+
): Extract<Types[Name], GraphQLInterfaceType>;
553599
/**
554600
* Gets a {@link GScalarType scalar type} from the existing GraphQL schema. If
555601
* there is no scalar type in the existing schema with the name passed, an
@@ -578,7 +624,9 @@ export type BaseSchemaMeta = {
578624
* }))(originalSchema);
579625
* ```
580626
*/
581-
scalar(name: string): GScalarType<unknown>;
627+
scalar<Name extends TypeOfKind<Types, GraphQLScalarType<any>>>(
628+
name: Name
629+
): Extract<Types[Name], GraphQLScalarType<any>>;
582630
};
583631

584632
function findObjectTypeUsages(

0 commit comments

Comments
 (0)