Skip to content

Commit 6d919d5

Browse files
committed
Typed base schema meta
1 parent 161aacb commit 6d919d5

File tree

1 file changed

+97
-31
lines changed

1 file changed

+97
-31
lines changed

packages/extend/src/index.ts

Lines changed: 97 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ const builtinScalars = new Set(specifiedScalarTypes.map((x) => x.name));
9797
* }
9898
* ```
9999
*/
100-
export function extend(
100+
export function extend<Types extends Record<string, NamedType>>(
101101
extension:
102102
| Extension
103103
| readonly Extension[]
104-
| ((base: BaseSchemaMeta) => Extension | readonly Extension[])
104+
| ((base: BaseSchemaMeta<Types>) => Extension | readonly Extension[])
105105
): (schema: GraphQLSchema) => GraphQLSchema {
106106
return (schema) => {
107107
const getType = (name: string) => {
@@ -119,76 +119,99 @@ export function extend(
119119
typeof extension === "function"
120120
? extension({
121121
schema,
122+
all(name) {
123+
const graphQLType = getType(name as string);
124+
if (isObjectType(graphQLType)) {
125+
return wrap.object(graphQLType) as any;
126+
}
127+
if (isInputObjectType(graphQLType)) {
128+
return wrap.inputObject(graphQLType) as any;
129+
}
130+
if (isEnumType(graphQLType)) {
131+
return wrap.enum(graphQLType) as any;
132+
}
133+
if (isInterfaceType(graphQLType)) {
134+
return wrap.interface(graphQLType) as any;
135+
}
136+
if (isScalarType(graphQLType)) {
137+
return wrap.scalar(graphQLType) as any;
138+
}
139+
if (isUnionType(graphQLType)) {
140+
return wrap.union(graphQLType) as any;
141+
}
142+
},
122143
object(name) {
123-
const graphQLType = getType(name);
144+
const graphQLType = getType(name as string);
124145
if (!isObjectType(graphQLType)) {
125146
throw new Error(
126147
`There is a type named ${JSON.stringify(
127148
name
128149
)} in the schema being extended but it is not an object type`
129150
);
130151
}
131-
return wrap.object(graphQLType);
152+
return wrap.object(graphQLType) as any;
132153
},
133154
inputObject(name) {
134-
const graphQLType = getType(name);
155+
const graphQLType = getType(name as string);
135156
if (!isInputObjectType(graphQLType)) {
136157
throw new Error(
137158
`There is a type named ${JSON.stringify(
138159
name
139160
)} in the schema being extended but it is not an input object type`
140161
);
141162
}
142-
return wrap.inputObject(graphQLType);
163+
return wrap.inputObject(graphQLType) as any;
143164
},
144165
enum(name) {
145-
const graphQLType = getType(name);
166+
const graphQLType = getType(name as string);
146167
if (!isEnumType(graphQLType)) {
147168
throw new Error(
148169
`There is a type named ${JSON.stringify(
149170
name
150171
)} in the schema being extended but it is not an enum type`
151172
);
152173
}
153-
return wrap.enum(graphQLType);
174+
return wrap.enum(graphQLType) as any;
154175
},
155176
interface(name) {
156-
const graphQLType = getType(name);
177+
const graphQLType = getType(name as string);
157178
if (!isInterfaceType(graphQLType)) {
158179
throw new Error(
159180
`There is a type named ${JSON.stringify(
160181
name
161182
)} in the schema being extended but it is not an interface type`
162183
);
163184
}
164-
return wrap.interface(graphQLType);
185+
return wrap.interface(graphQLType) as any;
165186
},
166187
scalar(name) {
167-
if (builtinScalars.has(name)) {
188+
if (builtinScalars.has(name as string)) {
168189
throw new Error(
169-
`The names of built-in scalars cannot be passed to BaseSchemaInfo.scalar but ${name} was passed`
190+
`The names of built-in scalars cannot be passed to BaseSchemaInfo.scalar but ${
191+
name as string
192+
} was passed`
170193
);
171194
}
172-
const graphQLType = getType(name);
195+
const graphQLType = getType(name as string);
173196
if (!isScalarType(graphQLType)) {
174197
throw new Error(
175198
`There is a type named ${JSON.stringify(
176199
name
177200
)} in the schema being extended but it is not a scalar type`
178201
);
179202
}
180-
return wrap.scalar(graphQLType);
203+
return wrap.scalar(graphQLType) as any;
181204
},
182205
union(name) {
183-
const graphQLType = getType(name);
206+
const graphQLType = getType(name as string);
184207
if (!isUnionType(graphQLType)) {
185208
throw new Error(
186209
`There is a type named ${JSON.stringify(
187210
name
188211
)} in the schema being extended but it is not a union type`
189212
);
190213
}
191-
return wrap.union(graphQLType);
214+
return wrap.union(graphQLType) as any;
192215
},
193216
})
194217
: extension
@@ -434,13 +457,52 @@ export type Extension = {
434457
// unreferencedConcreteInterfaceImplementations?: ObjectType<Context, any>[];
435458
};
436459

460+
export type NamedType =
461+
| ObjectType<any, unknown>
462+
| InputObjectType<{ [key: string]: Arg<InputType, boolean> }>
463+
| EnumType<Record<string, EnumValue<unknown>>>
464+
| UnionType<unknown, unknown>
465+
| InterfaceType<
466+
unknown,
467+
Record<string, InterfaceField<any, OutputType<unknown>, unknown>>,
468+
unknown
469+
>
470+
| ScalarType<unknown>;
471+
472+
export type NamedTypes = Record<string & {}, NamedType>;
473+
474+
type TypeOfKind<
475+
Types extends Record<string, NamedType>,
476+
Kind extends NamedType["kind"]
477+
> = {
478+
[K in keyof Types]: Types extends unknown
479+
? Kind extends Types[K]["kind"]
480+
? K
481+
: never
482+
: never;
483+
}[keyof Types];
484+
485+
type OnlyOfKind<
486+
Type extends NamedType,
487+
Kind extends NamedType["kind"]
488+
> = Type extends { kind: Kind } ? Type : never;
489+
437490
/**
438491
* This object contains the schema being extended and functions to get wrapped
439492
*
440493
* Note that the just like {@link wrap}, all of the GraphQL types returned
441494
*/
442-
export type BaseSchemaMeta = {
495+
export type BaseSchemaMeta<
496+
Types extends Record<string, NamedType> = NamedTypes
497+
> = {
443498
schema: GraphQLSchema;
499+
all<
500+
Name extends {
501+
[K in keyof Types]: string extends K ? never : K;
502+
}[keyof Types]
503+
>(
504+
name: Name
505+
): Types[Name];
444506
/**
445507
* Gets an object type from the existing GraphQL schema and wraps it in an
446508
* {@link ObjectType}. If there is no object type in the existing schema with
@@ -461,7 +523,9 @@ export type BaseSchemaMeta = {
461523
* }))(originalSchema);
462524
* ```
463525
*/
464-
object(name: string): ObjectType<unknown, unknown>;
526+
object<Name extends TypeOfKind<Types, "object">>(
527+
name: Name
528+
): OnlyOfKind<Types[Name], "object">;
465529
/**
466530
* Gets an input object type from the existing GraphQL schema and wraps it in
467531
* an {@link InputObjectType}. If there is no input object type in the existing
@@ -488,9 +552,9 @@ export type BaseSchemaMeta = {
488552
* }))(originalSchema);
489553
* ```
490554
*/
491-
inputObject(
492-
name: string
493-
): InputObjectType<{ [key: string]: Arg<InputType, boolean> }>;
555+
inputObject<Name extends TypeOfKind<Types, "input">>(
556+
name: Name
557+
): OnlyOfKind<Types[Name], "input">;
494558
/**
495559
* Gets an enum type from the existing GraphQL schema and wraps it in an
496560
* {@link EnumType}. If there is no enum type in the existing schema with the
@@ -516,7 +580,9 @@ export type BaseSchemaMeta = {
516580
* }))(originalSchema);
517581
* ```
518582
*/
519-
enum(name: string): EnumType<Record<string, EnumValue<unknown>>>;
583+
enum<Name extends TypeOfKind<Types, "enum">>(
584+
name: Name
585+
): OnlyOfKind<Types[Name], "enum">;
520586
/**
521587
* Gets a union type from the existing GraphQL schema and wraps it in an
522588
* {@link UnionType}. If there is no union type in the existing schema with the
@@ -537,7 +603,9 @@ export type BaseSchemaMeta = {
537603
* }))(originalSchema);
538604
* ```
539605
*/
540-
union(name: string): UnionType<unknown, unknown>;
606+
union<Name extends TypeOfKind<Types, "union">>(
607+
name: Name
608+
): OnlyOfKind<Types[Name], "union">;
541609
/**
542610
* Gets an interface type from the existing GraphQL schema and wraps it in an
543611
* {@link InterfaceType}. If there is no interface type in the existing schema
@@ -558,13 +626,9 @@ export type BaseSchemaMeta = {
558626
* }))(originalSchema);
559627
* ```
560628
*/
561-
interface(
562-
name: string
563-
): InterfaceType<
564-
unknown,
565-
Record<string, InterfaceField<any, OutputType<unknown>, unknown>>,
566-
unknown
567-
>;
629+
interface<Name extends TypeOfKind<Types, "interface">>(
630+
name: Name
631+
): OnlyOfKind<Types[Name], "interface">;
568632
/**
569633
* Gets a scalar type from the existing GraphQL schema and wraps it in an
570634
* {@link ScalarType}. If there is no scalar type in the existing schema with
@@ -592,7 +656,9 @@ export type BaseSchemaMeta = {
592656
* }))(originalSchema);
593657
* ```
594658
*/
595-
scalar(name: string): ScalarType<unknown>;
659+
scalar<Name extends TypeOfKind<Types, "scalar">>(
660+
name: Name
661+
): OnlyOfKind<Types[Name], "scalar">;
596662
};
597663

598664
function getGraphQLJSFieldsFromGraphQLTSFields(

0 commit comments

Comments
 (0)