diff --git a/.changeset/tiny-cameras-battle.md b/.changeset/tiny-cameras-battle.md new file mode 100644 index 00000000..565afe8a --- /dev/null +++ b/.changeset/tiny-cameras-battle.md @@ -0,0 +1,5 @@ +--- +'gql.tada': patch +--- + +Remove redundant constraint on `IntrospectionQuery` data. When the full type is used as an `extends`, the input type (which can be a huge schema), is checked against this type, which forces a full evaluation. This means that TypeScript may spend multiple seconds in `recursiveTypeRelatedTo`. This work has been eliminated and should help performance. diff --git a/src/__tests__/fixtures/simpleSchema.ts b/src/__tests__/fixtures/simpleSchema.ts index 5a2056c8..a16c3d12 100644 --- a/src/__tests__/fixtures/simpleSchema.ts +++ b/src/__tests__/fixtures/simpleSchema.ts @@ -7,11 +7,9 @@ export type simpleSchema = { Query: { kind: 'OBJECT'; name: 'Query'; - interfaces: never; fields: { todos: { name: 'todos'; - args: any; type: { kind: 'LIST'; name: null; @@ -24,7 +22,6 @@ export type simpleSchema = { }; latestTodo: { name: 'latestTodo'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -37,7 +34,6 @@ export type simpleSchema = { }; test: { name: 'test'; - args: any; type: { kind: 'UNION'; name: 'Search'; @@ -66,7 +62,6 @@ export type simpleSchema = { fields: { id: { name: 'id'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -79,7 +74,6 @@ export type simpleSchema = { }; text: { name: 'text'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -92,7 +86,6 @@ export type simpleSchema = { }; complete: { name: 'complete'; - args: any; type: { kind: 'SCALAR'; name: 'Boolean'; @@ -101,7 +94,6 @@ export type simpleSchema = { }; author: { name: 'author'; - args: any; type: { kind: 'OBJECT'; name: 'Author'; @@ -110,7 +102,6 @@ export type simpleSchema = { }; maxLength: { name: 'maxLength'; - args: any; type: { kind: 'SCALAR'; name: 'Int'; @@ -118,7 +109,6 @@ export type simpleSchema = { }; }; }; - interfaces: 'ITodo'; }; BigTodo: { @@ -127,7 +117,6 @@ export type simpleSchema = { fields: { id: { name: 'id'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -140,7 +129,6 @@ export type simpleSchema = { }; text: { name: 'text'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -153,7 +141,6 @@ export type simpleSchema = { }; complete: { name: 'complete'; - args: any; type: { kind: 'SCALAR'; name: 'Boolean'; @@ -162,7 +149,6 @@ export type simpleSchema = { }; author: { name: 'author'; - args: any; type: { kind: 'OBJECT'; name: 'Author'; @@ -171,7 +157,6 @@ export type simpleSchema = { }; wallOfText: { name: 'wallOfText'; - args: any; type: { kind: 'SCALAR'; name: 'String'; @@ -179,18 +164,15 @@ export type simpleSchema = { }; }; }; - interfaces: 'ITodo'; }; ITodo: { kind: 'INTERFACE'; name: 'ITodo'; - interfaces: never; possibleTypes: 'BigTodo' | 'SmallTodo'; fields: { id: { name: 'id'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -203,7 +185,6 @@ export type simpleSchema = { }; text: { name: 'text'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -216,7 +197,6 @@ export type simpleSchema = { }; complete: { name: 'complete'; - args: any; type: { kind: 'SCALAR'; name: 'Boolean'; @@ -225,7 +205,6 @@ export type simpleSchema = { }; author: { name: 'author'; - args: any; type: { kind: 'OBJECT'; name: 'Author'; @@ -274,11 +253,9 @@ export type simpleSchema = { NoTodosError: { kind: 'OBJECT'; name: 'NoTodosError'; - interfaces: never; fields: { message: { name: 'message'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -295,11 +272,9 @@ export type simpleSchema = { Todo: { kind: 'OBJECT'; name: 'Todo'; - interfaces: never; fields: { id: { name: 'id'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -312,7 +287,6 @@ export type simpleSchema = { }; text: { name: 'text'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -325,7 +299,6 @@ export type simpleSchema = { }; complete: { name: 'complete'; - args: any; type: { kind: 'SCALAR'; name: 'Boolean'; @@ -334,7 +307,6 @@ export type simpleSchema = { }; test: { name: 'test'; - args: any; type: { kind: 'ENUM'; name: 'test'; @@ -343,7 +315,6 @@ export type simpleSchema = { }; author: { name: 'author'; - args: any; type: { kind: 'OBJECT'; name: 'Author'; @@ -376,11 +347,9 @@ export type simpleSchema = { Author: { kind: 'OBJECT'; name: 'Author'; - interfaces: never; fields: { id: { name: 'id'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -393,7 +362,6 @@ export type simpleSchema = { }; name: { name: 'name'; - args: any; type: { kind: 'NON_NULL'; name: null; @@ -406,7 +374,6 @@ export type simpleSchema = { }; known: { name: 'known'; - args: any; type: { kind: 'SCALAR'; name: 'Boolean'; @@ -419,11 +386,9 @@ export type simpleSchema = { Mutation: { kind: 'OBJECT'; name: 'Mutation'; - interfaces: never; fields: { toggleTodo: { name: 'toggleTodo'; - args: any; type: { kind: 'OBJECT'; name: 'Todo'; @@ -432,7 +397,6 @@ export type simpleSchema = { }; updateTodo: { name: 'updateTodo'; - args: any; type: { kind: 'SCALAR'; name: 'Boolean'; @@ -445,11 +409,9 @@ export type simpleSchema = { Subscription: { kind: 'OBJECT'; name: 'Subscription'; - interfaces: never; fields: { newTodo: { name: 'newTodo'; - args: any; type: { kind: 'OBJECT'; name: 'Todo'; diff --git a/src/introspection.ts b/src/introspection.ts index bef434bc..264b6ffe 100644 --- a/src/introspection.ts +++ b/src/introspection.ts @@ -17,17 +17,20 @@ interface IntrospectionSchema { readonly queryType: IntrospectionNamedTypeRef; readonly mutationType?: IntrospectionNamedTypeRef | null; readonly subscriptionType?: IntrospectionNamedTypeRef | null; - readonly types: readonly IntrospectionType[]; + /* Usually this would be: + | IntrospectionScalarType + | IntrospectionObjectType + | IntrospectionInterfaceType + | IntrospectionUnionType + | IntrospectionEnumType + | IntrospectionInputObjectType; + However, this forces TypeScript to evaluate the type of an + entire introspection query, rather than accept its shape as-is. + So, instead, we constrain it to `any` here. + */ + readonly types: readonly any[]; } -export type IntrospectionType = - | IntrospectionScalarType - | IntrospectionObjectType - | IntrospectionInterfaceType - | IntrospectionUnionType - | IntrospectionEnumType - | IntrospectionInputObjectType; - interface IntrospectionScalarType { readonly kind: 'SCALAR'; readonly name: string; @@ -37,16 +40,20 @@ interface IntrospectionScalarType { export interface IntrospectionObjectType { readonly kind: 'OBJECT'; readonly name: string; - readonly fields: readonly IntrospectionField[]; - readonly interfaces: readonly IntrospectionNamedTypeRef[] | never; + // Usually this would be `IntrospectionField`. + // However, to save TypeScript some work, instead, we constraint it to `any` here. + readonly fields: readonly any[]; + // The `interfaces` field isn't used. It's omitted here } interface IntrospectionInterfaceType { readonly kind: 'INTERFACE'; readonly name: string; - readonly fields: readonly IntrospectionField[]; + // Usually this would be `IntrospectionField`. + // However, to save TypeScript some work, instead, we constraint it to `any` here. + readonly fields: readonly any[]; readonly possibleTypes: readonly IntrospectionNamedTypeRef[]; - readonly interfaces?: readonly IntrospectionNamedTypeRef[] | null; + // The `interfaces` field isn't used. It's omitted here } interface IntrospectionUnionType { @@ -92,8 +99,8 @@ export interface IntrospectionNamedTypeRef { export interface IntrospectionField { readonly name: string; - readonly args: readonly IntrospectionInputValue[]; readonly type: IntrospectionTypeRef; + // The `args` field isn't used. It's omitted here } interface IntrospectionInputValue { @@ -132,14 +139,12 @@ type mapField = T extends IntrospectionField ? { name: T['name']; type: T['type']; - args: any; } : never; export type mapObject = { kind: 'OBJECT'; name: T['name']; - interfaces: T['interfaces'][number]['name']; fields: obj<{ [P in T['fields'][number]['name']]: T['fields'][number] extends infer Field ? Field extends { readonly name: P } @@ -158,7 +163,6 @@ export type mapInputObject = { type mapInterface = { kind: 'INTERFACE'; name: T['name']; - interfaces: T['interfaces'] extends readonly any[] ? T['interfaces'][number]['name'] : never; possibleTypes: T['possibleTypes'][number]['name']; fields: obj<{ [P in T['fields'][number]['name']]: T['fields'][number] extends infer Field @@ -224,8 +228,8 @@ export type ScalarsLike = { export type IntrospectionLikeType = { query: string; - mutation: string | never; - subscription: string | never; + mutation?: any; + subscription?: any; types: { [name: string]: any }; };