Skip to content

Commit 46d3bb5

Browse files
committed
Typed base schema meta
1 parent 7e28b75 commit 46d3bb5

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
@@ -416,7 +416,7 @@ test("using an existing object type", () => {
416416
`);
417417
});
418418

419-
test("errors when no type ", () => {
419+
test("errors when no type exists with that name", () => {
420420
expect(() => {
421421
extend((base) => ({
422422
query: {
@@ -522,7 +522,9 @@ test(".scalar works for custom scalars", () => {
522522
},
523523
}),
524524
});
525-
const extended = extend((base) => ({
525+
const extended = extend<{
526+
Something: typeof Something;
527+
}>((base) => ({
526528
query: {
527529
hello: g.field({
528530
type: base.scalar("Something"),

packages/extend/src/index.ts

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

3135
import {
3236
g,
3337
GField,
3438
GObjectType,
35-
GArg,
3639
GEnumType,
3740
GUnionType,
3841
GInterfaceType,
3942
GScalarType,
4043
GOutputType,
4144
GInputObjectType,
45+
GInputType,
46+
GArg,
47+
GInterfaceField,
4248
} from "@graphql-ts/schema";
4349

4450
const builtinScalars = new Set(specifiedScalarTypes.map((x) => x.name));
@@ -92,11 +98,11 @@ const builtinScalars = new Set(specifiedScalarTypes.map((x) => x.name));
9298
* }
9399
* ```
94100
*/
95-
export function extend(
101+
export function extend<Types extends Record<string, NamedType>>(
96102
extension:
97103
| Extension
98104
| readonly Extension[]
99-
| ((base: BaseSchemaMeta) => Extension | readonly Extension[])
105+
| ((base: BaseSchemaMeta<Types>) => Extension | readonly Extension[])
100106
): (schema: GraphQLSchema) => GraphQLSchema {
101107
return (schema) => {
102108
const getType = (name: string) => {
@@ -114,76 +120,81 @@ export function extend(
114120
typeof extension === "function"
115121
? extension({
116122
schema,
123+
all(name) {
124+
return getType(name as string) as any;
125+
},
117126
object(name) {
118-
const graphQLType = getType(name);
127+
const graphQLType = getType(name as string);
119128
if (!isObjectType(graphQLType)) {
120129
throw new Error(
121130
`There is a type named ${JSON.stringify(
122131
name
123132
)} in the schema being extended but it is not an object type`
124133
);
125134
}
126-
return graphQLType;
135+
return graphQLType as any;
127136
},
128137
inputObject(name) {
129-
const graphQLType = getType(name);
138+
const graphQLType = getType(name as string);
130139
if (!isInputObjectType(graphQLType)) {
131140
throw new Error(
132141
`There is a type named ${JSON.stringify(
133142
name
134143
)} in the schema being extended but it is not an input object type`
135144
);
136145
}
137-
return graphQLType;
146+
return graphQLType as any;
138147
},
139148
enum(name) {
140-
const graphQLType = getType(name);
149+
const graphQLType = getType(name as string);
141150
if (!isEnumType(graphQLType)) {
142151
throw new Error(
143152
`There is a type named ${JSON.stringify(
144153
name
145154
)} in the schema being extended but it is not an enum type`
146155
);
147156
}
148-
return graphQLType;
157+
return graphQLType as any;
149158
},
150159
interface(name) {
151-
const graphQLType = getType(name);
160+
const graphQLType = getType(name as string);
152161
if (!isInterfaceType(graphQLType)) {
153162
throw new Error(
154163
`There is a type named ${JSON.stringify(
155164
name
156165
)} in the schema being extended but it is not an interface type`
157166
);
158167
}
159-
return graphQLType;
168+
return graphQLType as any;
160169
},
161170
scalar(name) {
162-
if (builtinScalars.has(name)) {
171+
if (builtinScalars.has(name as string)) {
163172
throw new Error(
164-
`The names of built-in scalars cannot be passed to BaseSchemaInfo.scalar but ${name} was passed`
173+
`The names of built-in scalars cannot be passed to BaseSchemaInfo.scalar but ${
174+
name as string
175+
} was passed`
165176
);
166177
}
167-
const graphQLType = getType(name);
178+
const graphQLType = getType(name as string);
168179
if (!isScalarType(graphQLType)) {
169180
throw new Error(
170181
`There is a type named ${JSON.stringify(
171182
name
172183
)} in the schema being extended but it is not a scalar type`
173184
);
174185
}
175-
return graphQLType;
186+
return graphQLType as any;
176187
},
177188
union(name) {
178-
const graphQLType = getType(name);
189+
const graphQLType = getType(name as string);
179190
if (!isUnionType(graphQLType)) {
180191
throw new Error(
181192
`There is a type named ${JSON.stringify(
182193
name
183194
)} in the schema being extended but it is not a union type`
184195
);
185196
}
186-
return graphQLType;
197+
return graphQLType as any;
187198
},
188199
})
189200
: extension
@@ -427,12 +438,39 @@ export type Extension = {
427438
// unreferencedConcreteInterfaceImplementations?: ObjectType<Context, any>[];
428439
};
429440

441+
export type NamedType =
442+
| GObjectType<any, unknown>
443+
| GInputObjectType<{ [key: string]: GArg<GInputType, boolean> }>
444+
| GEnumType<Record<string, unknown>>
445+
| GUnionType<unknown, unknown>
446+
| GInterfaceType<
447+
unknown,
448+
Record<string, GInterfaceField<any, GOutputType<unknown>, unknown>>,
449+
unknown
450+
>
451+
| GScalarType<unknown>;
452+
453+
export type NamedTypes = Record<string & {}, NamedType>;
454+
455+
type TypeOfKind<Types extends Record<string, NamedType>, Constraint> = {
456+
[K in keyof Types]: Extract<Types[K], Constraint> extends never ? never : K;
457+
}[keyof Types];
458+
430459
/**
431460
* This object contains the schema being extended and functions to get GraphQL
432461
* types from the schema.
433462
*/
434-
export type BaseSchemaMeta = {
463+
export type BaseSchemaMeta<
464+
Types extends Record<string, NamedType> = NamedTypes,
465+
> = {
435466
schema: GraphQLSchema;
467+
all<
468+
Name extends {
469+
[K in keyof Types]: string extends K ? never : K;
470+
}[keyof Types],
471+
>(
472+
name: Name
473+
): Types[Name];
436474
/**
437475
* Gets an {@link GObjectType object type} from the existing GraphQL schema. If
438476
* there is no object type in the existing schema with the name passed, an
@@ -453,7 +491,9 @@ export type BaseSchemaMeta = {
453491
* }))(originalSchema);
454492
* ```
455493
*/
456-
object(name: string): GObjectType<unknown, unknown>;
494+
object<Name extends TypeOfKind<Types, GraphQLObjectType>>(
495+
name: Name
496+
): Extract<Types[Name], GraphQLObjectType>;
457497
/**
458498
* Gets an {@link GInputObjectType input object type} from the existing GraphQL
459499
* schema. If there is no input object type in the existing schema with the
@@ -480,9 +520,9 @@ export type BaseSchemaMeta = {
480520
* }))(originalSchema);
481521
* ```
482522
*/
483-
inputObject(
484-
name: string
485-
): GInputObjectType<{ [key: string]: GArg<any, boolean> }, boolean>;
523+
inputObject<Name extends TypeOfKind<Types, GraphQLInputObjectType>>(
524+
name: Name
525+
): Extract<Types[Name], GraphQLInputObjectType>;
486526
/**
487527
* Gets an {@link GEnumType enum type} from the existing GraphQL schema. If
488528
* there is no enum type in the existing schema with the name passed, an error
@@ -508,7 +548,9 @@ export type BaseSchemaMeta = {
508548
* }))(originalSchema);
509549
* ```
510550
*/
511-
enum(name: string): GEnumType<Record<string, unknown>>;
551+
enum<Name extends TypeOfKind<Types, GEnumType<any>>>(
552+
name: Name
553+
): Extract<Types[Name], GEnumType<any>>;
512554
/**
513555
* Gets a {@link GUnionType union type} from the existing GraphQL schema. If
514556
* there is no union type in the existing schema with the name passed, an
@@ -529,7 +571,9 @@ export type BaseSchemaMeta = {
529571
* }))(originalSchema);
530572
* ```
531573
*/
532-
union(name: string): GUnionType<unknown, unknown>;
574+
union<Name extends TypeOfKind<Types, GraphQLUnionType>>(
575+
name: Name
576+
): Extract<Types[Name], GraphQLUnionType>;
533577
/**
534578
* Gets an {@link GInterfaceType interface type} from the existing GraphQL
535579
* schema. If there is no interface type in the existing schema with the name
@@ -550,7 +594,9 @@ export type BaseSchemaMeta = {
550594
* }))(originalSchema);
551595
* ```
552596
*/
553-
interface(name: string): GInterfaceType<unknown, any, unknown>;
597+
interface<Name extends TypeOfKind<Types, GraphQLInterfaceType>>(
598+
name: Name
599+
): Extract<Types[Name], GraphQLInterfaceType>;
554600
/**
555601
* Gets a {@link GScalarType scalar type} from the existing GraphQL schema. If
556602
* there is no scalar type in the existing schema with the name passed, an
@@ -579,7 +625,9 @@ export type BaseSchemaMeta = {
579625
* }))(originalSchema);
580626
* ```
581627
*/
582-
scalar(name: string): GScalarType<unknown>;
628+
scalar<Name extends TypeOfKind<Types, GraphQLScalarType<any>>>(
629+
name: Name
630+
): Extract<Types[Name], GraphQLScalarType<any>>;
583631
};
584632

585633
function findObjectTypeUsages(

0 commit comments

Comments
 (0)