Input Object Types
Input objects are used to represent the input arguments of a field. They are similar to object types, but they are used to represent inputs instead of output fields. Input object types use g.arg
similar to how args are defined on output fields rather than using the g.field
function like on output object types.
const const UserCreateInput: GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}, false>
UserCreateInput = const g: GWithContext<Context>
g.inputObject: <{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}, false>(config: { ...;}) => GInputObjectType<...>
inputObject({ name: string
name: "UserCreateInput", fields: { name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;} | (() => { name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;})
fields: { name: GArg<GNonNull<GScalarType<string, string>>, false>
name: const g: GWithContext<Context>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<Context>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<Context>
g.type String: GScalarType<string, string>
String) }), email: GArg<GNonNull<GScalarType<string, string>>, false>
email: const g: GWithContext<Context>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<Context>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<Context>
g.type String: GScalarType<string, string>
String) }), },});
const const Mutation: GObjectType<unknown, Context>
Mutation = const g: GWithContext<Context>
g.object: <unknown>(youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction?: { youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction: true;}) => <Fields, Interfaces>(config: { ...;} & Omit<...>) => GObjectType<...>
object()({ name: string
name: "Mutation", fields: { createUser: GField<unknown, { input: GArg<GNonNull<GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>; }, false>>, false>; }, GObjectType<...>, unknown, Context>;} | (() => { createUser: GField<unknown, { input: GArg<GNonNull<GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>; }, false>>, false>; }, GObjectType<...>, unknown, Context>;})
fields: { createUser: GField<unknown, { input: GArg<GNonNull<GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>; }, false>>, false>;}, GObjectType<...>, unknown, Context>
createUser: const g: GWithContext<Context>
g.field: <unknown, GObjectType<UserSource, Context>, (source: unknown, args: { readonly input: { readonly name: string; readonly email: string; };}, context: Context) => UserSource, { ...;}>(field: FieldFuncArgs<...> & { ...;}) => GField<...>
field({ type: GObjectType<UserSource, Context>
type: const User: GObjectType<UserSource, Context>
User, args?: { input: GArg<GNonNull<GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>; }, false>>, false>;}
args: { input: GArg<GNonNull<GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}, false>>, false>
input: const g: GWithContext<Context>
g.arg: <GNonNull<GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}, false>>, undefined>(arg: { ...;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}, false>>
type: const g: GWithContext<Context>
g.nonNull: <GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}, false>>(of: GInputObjectType<...>) => GNonNull<...>
nonNull(const UserCreateInput: GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}, false>
UserCreateInput) }), }, resolve: ((source: unknown, args: { readonly input: { readonly name: string; readonly email: string; };}, context: Context, info: GraphQLResolveInfo) => InferValueFromOutputType<...>) & ((source: unknown, args: { ...;}, context: Context) => UserSource)
resolve: (source: unknown
source, args: { readonly input: { readonly name: string; readonly email: string; };}
args, context: Context
context) => { return context: Context
context.createUser: (input: { name: string; email: string;}) => UserSource
createUser(args: { readonly input: { readonly name: string; readonly email: string; };}
args.input);input: { readonly name: string; readonly email: string;}
}, }), },});
type Mutation { createUser(input: UserCreateInput!): User}
type User { id: ID! name: String! email: String!}
input UserCreateInput { name: String! email: String!}
Circular Types
While circular input object types are less common than circular Object Types, they can still occur. Just like with circular object types, we need to start by making fields
a function:
const UserCreateInput = const g: GWithContext<unknown>
g.inputObject: <any, false>(config: { name: string; description?: Maybe<string>; extensions?: Maybe<Readonly<GraphQLInputObjectTypeExtensions>>; astNode?: Maybe<...>; extensionASTNodes?: Maybe<...>; isOneOf?: false; fields: any;}) => GInputObjectType<...>
inputObject({Error ts(7022) ― name: string
name: "UserCreateInput", fields: () => ({Error ts(7023) ― name: GArg<GNonNull<GScalarType<string, string>>, false>
name: const g: GWithContext<unknown>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<unknown>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String) }), email: GArg<GNonNull<GScalarType<string, string>>, false>
email: const g: GWithContext<unknown>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<unknown>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String) }), friends: GArg<GList<GNonNull<any>>, false>
friends: const g: GWithContext<unknown>
g.arg: <GList<GNonNull<any>>, undefined>(arg: { type: GList<GNonNull<any>>; description?: Maybe<string>; extensions?: (Readonly<GraphQLInputFieldExtensions> & Readonly<...>) | null | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GList<GNonNull<any>>
type: const g: GWithContext<unknown>
g.list: <GNonNull<any>>(of: GNonNull<any>) => GList<GNonNull<any>>
list(const g: GWithContext<unknown>
g.nonNull: <any>(of: any) => GNonNull<any>
nonNull(const UserCreateInput: any
UserCreateInput)) }), }),});
input UserCreateInput { name: String! email: String! friends: [UserCreateInput!]}
To resolve TypeScript’s errors about circularity though, we unfortunately can’t use the g
type like we did with object types. Instead, we need to use the GInputObjectType
type and we also need to essentially duplicate the fields definition in the types
import type { type GArg<Type extends GInputType, HasDefaultValue extends boolean = boolean> = { type: Type; defaultValue: { true: {} | null; false: undefined; }[`${HasDefaultValue}`]; description?: Maybe<string>; deprecationReason?: Maybe<string>; extensions?: Maybe<...>; astNode?: Maybe<...>;}
GArg, class GNonNull<Of extends GNullableType<any>>
GNonNull, class GList<Of extends GType<any>>
GList, class GInputObjectType<Fields extends { [key: string]: IsOneOf extends true ? GArg<GNullableInputType, false> : GArg<GInputType>; }, IsOneOf extends boolean = false>
GInputObjectType,} from "@graphql-ts/schema";
type type UserCreateInput = GInputObjectType<{ name: GArg<GNonNull<typeof g.String>>; email: g<typeof g.arg<g<typeof g.nonNull<typeof g.String>>>>; friends: GArg<GList<GNonNull<UserCreateInput>>>;}, false>
UserCreateInput = class GInputObjectType<Fields extends { [key: string]: IsOneOf extends true ? GArg<GNullableInputType, false> : GArg<GInputType>; }, IsOneOf extends boolean = false>
GInputObjectType<{ // you can use the G* types from @graphql-ts/schema to define the fields name: GArg<GNonNull<GScalarType<string, string>>>
name: type GArg<Type extends GInputType, HasDefaultValue extends boolean = boolean> = { type: Type; defaultValue: { true: {} | null; false: undefined; }[`${HasDefaultValue}`]; description?: Maybe<string>; deprecationReason?: Maybe<string>; extensions?: Maybe<...>; astNode?: Maybe<...>;}
GArg<class GNonNull<Of extends GNullableType<any>>
GNonNull<typeof const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String>>; // or you can use the g type and g.* functions email: GArg<GNonNull<GScalarType<string, string>>, false>
email: type g<T> = T extends () => (args: any) => infer R ? R : T extends (args: any) => infer R ? R : never
g<typeof const g: GWithContext<unknown>
g.arg: <Type extends GInputType, DefaultValue extends InferValueFromInputType<Type> | undefined = undefined>(arg: { ...;} & (undefined extends DefaultValue ? { defaultValue?: DefaultValue;} : { defaultValue: DefaultValue;})) => GArg<Type, DefaultValue extends undefined ? false : true>
arg<type g<T> = T extends () => (args: any) => infer R ? R : T extends (args: any) => infer R ? R : never
g<typeof const g: GWithContext<unknown>
g.nonNull: <Of extends GNullableType<any>>(of: Of) => GNonNull<Of>
nonNull<typeof const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String>>>>; friends: GArg<GList<GNonNull<UserCreateInput>>>
friends: type GArg<Type extends GInputType, HasDefaultValue extends boolean = boolean> = { type: Type; defaultValue: { true: {} | null; false: undefined; }[`${HasDefaultValue}`]; description?: Maybe<string>; deprecationReason?: Maybe<string>; extensions?: Maybe<...>; astNode?: Maybe<...>;}
GArg<class GList<Of extends GType<any>>
GList<class GNonNull<Of extends GNullableType<any>>
GNonNull<type UserCreateInput = GInputObjectType<{ name: GArg<GNonNull<typeof g.String>>; email: g<typeof g.arg<g<typeof g.nonNull<typeof g.String>>>>; friends: GArg<GList<GNonNull<UserCreateInput>>>;}, false>
UserCreateInput>>>;}>;
const const UserCreateInput: UserCreateInput
UserCreateInput: type UserCreateInput = GInputObjectType<{ name: GArg<GNonNull<typeof g.String>>; email: g<typeof g.arg<g<typeof g.nonNull<typeof g.String>>>>; friends: GArg<GList<GNonNull<UserCreateInput>>>;}, false>
UserCreateInput = const g: GWithContext<unknown>
g.inputObject: <{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>; friends: GArg<...>;}, false>(config: { ...;}) => GInputObjectType<...>
inputObject({ name: string
name: "UserCreateInput", fields: { name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>; friends: GArg<...>;} | (() => { name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>; friends: GArg<...>;})
fields: () => ({ name: GArg<GNonNull<GScalarType<string, string>>, false>
name: const g: GWithContext<unknown>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; deprecationReason?: Maybe<...>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<unknown>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String) }), email: GArg<GNonNull<GScalarType<string, string>>, false>
email: const g: GWithContext<unknown>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; deprecationReason?: Maybe<...>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<unknown>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String) }), friends: GArg<GList<GNonNull<UserCreateInput>>, false>
friends: const g: GWithContext<unknown>
g.arg: <GList<GNonNull<UserCreateInput>>, undefined>(arg: { type: GList<GNonNull<UserCreateInput>>; description?: Maybe<...>; deprecationReason?: Maybe<...>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GList<GNonNull<UserCreateInput>>
type: const g: GWithContext<unknown>
g.list: <GNonNull<UserCreateInput>>(of: GNonNull<UserCreateInput>) => GList<GNonNull<UserCreateInput>>
list(const g: GWithContext<unknown>
g.nonNull: <UserCreateInput>(of: UserCreateInput) => GNonNull<UserCreateInput>
nonNull(const UserCreateInput: UserCreateInput
UserCreateInput)) }), }),});
input UserCreateInput { name: String! email: String! friends: [UserCreateInput!]}
Since most fields in input objects won’t be circular, you can also extract out the non-circular fields and use typeof
instead of duplicating the fields:
import type { type GArg<Type extends GInputType, HasDefaultValue extends boolean = boolean> = { type: Type; defaultValue: { true: {} | null; false: undefined; }[`${HasDefaultValue}`]; description?: Maybe<string>; deprecationReason?: Maybe<string>; extensions?: Maybe<...>; astNode?: Maybe<...>;}
GArg, class GNonNull<Of extends GNullableType<any>>
GNonNull, class GList<Of extends GType<any>>
GList, class GInputObjectType<Fields extends { [key: string]: IsOneOf extends true ? GArg<GNullableInputType, false> : GArg<GInputType>; }, IsOneOf extends boolean = false>
GInputObjectType,} from "@graphql-ts/schema";
const const userCreateInputFields: { name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}
userCreateInputFields = { name: GArg<GNonNull<GScalarType<string, string>>, false>
name: const g: GWithContext<unknown>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; deprecationReason?: Maybe<...>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<unknown>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String) }), email: GArg<GNonNull<GScalarType<string, string>>, false>
email: const g: GWithContext<unknown>
g.arg: <GNonNull<GScalarType<string, string>>, undefined>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; deprecationReason?: Maybe<...>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<unknown>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String) }),};
type type UserCreateInput = GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;} & { ...;}, false>
UserCreateInput = class GInputObjectType<Fields extends { [key: string]: IsOneOf extends true ? GArg<GNullableInputType, false> : GArg<GInputType>; }, IsOneOf extends boolean = false>
GInputObjectType< typeof const userCreateInputFields: { name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}
userCreateInputFields & { friends: GArg<GList<GNonNull<UserCreateInput>>>
friends: type GArg<Type extends GInputType, HasDefaultValue extends boolean = boolean> = { type: Type; defaultValue: { true: {} | null; false: undefined; }[`${HasDefaultValue}`]; description?: Maybe<string>; deprecationReason?: Maybe<string>; extensions?: Maybe<...>; astNode?: Maybe<...>;}
GArg<class GList<Of extends GType<any>>
GList<class GNonNull<Of extends GNullableType<any>>
GNonNull<type UserCreateInput = GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;} & { ...;}, false>
UserCreateInput>>>; }>;
const const UserCreateInput: UserCreateInput
UserCreateInput: type UserCreateInput = GInputObjectType<{ name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;} & { ...;}, false>
UserCreateInput = const g: GWithContext<unknown>
g.inputObject: <{ friends: GArg<GList<GNonNull<UserCreateInput>>, false>; name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<...>;}, false>(config: { ...;}) => GInputObjectType<...>
inputObject({ name: string
name: "UserCreateInput", fields: { friends: GArg<GList<GNonNull<UserCreateInput>>, false>; name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<...>;} | (() => { friends: GArg<GList<GNonNull<UserCreateInput>>, false>; name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<...>;})
fields: () => ({ ...const userCreateInputFields: { name: GArg<GNonNull<GScalarType<string, string>>, false>; email: GArg<GNonNull<GScalarType<string, string>>, false>;}
userCreateInputFields, friends: GArg<GList<GNonNull<UserCreateInput>>, false>
friends: const g: GWithContext<unknown>
g.arg: <GList<GNonNull<UserCreateInput>>, undefined>(arg: { type: GList<GNonNull<UserCreateInput>>; description?: Maybe<...>; deprecationReason?: Maybe<...>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GList<GNonNull<UserCreateInput>>
type: const g: GWithContext<unknown>
g.list: <GNonNull<UserCreateInput>>(of: GNonNull<UserCreateInput>) => GList<GNonNull<UserCreateInput>>
list(const g: GWithContext<unknown>
g.nonNull: <UserCreateInput>(of: UserCreateInput) => GNonNull<UserCreateInput>
nonNull(const UserCreateInput: UserCreateInput
UserCreateInput)) }), }),});
input UserCreateInput { name: String! email: String! friends: [UserCreateInput!]}
Nullability & Default Values
Input objects can also have default values for their arguments. Default values are used when the argument is not provided in the input object. Default values can be provided using the defaultValue
property in the g.arg
function. We’re going to demonstrate by using args
on a field rather than on an input object type but the same concept applies to input object types.
To start with, since all types are nullable in GraphQL by default, let’s look at what the type of a nullable type is:
const const field: GField<unknown, { name: GArg<GScalarType<string, string>, false>;}, GScalarType<string, string>, unknown, unknown>
field = const g: GWithContext<unknown>
g.field: <unknown, GScalarType<string, string>, (_: unknown, args: { readonly name: string | null | undefined;}) => string | null | undefined, { name: GArg<GScalarType<string, string>, false>;}>(field: FieldFuncArgs<...> & { ...;}) => GField<...>
field({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String, args?: { name: GArg<GScalarType<string, string>, false>;}
args: { name: GArg<GScalarType<string, string>, false>
name: const g: GWithContext<unknown>
g.arg: <GScalarType<string, string>, undefined>(arg: { type: GScalarType<string, string>; description?: Maybe<string>; deprecationReason?: Maybe<string>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String }), }, resolve: ((source: unknown, args: { readonly name: string | null | undefined;}, context: unknown, info: GraphQLResolveInfo) => InferValueFromOutputType<GScalarType<string, string>>) & ((_: unknown, args: { ...;}) => string | ... 1 more ... | undefined)
resolve(_: unknown
_, args) {args: { readonly name: string | null | undefined;}
return args: { readonly name: string | null | undefined;}
args.name: string | null | undefined
name; },});
type Query { field(name: String): String}
For the String
scalar, the type is string | null | undefined
.
This is because for a nullable input type, there are three possible options for a consumer of a GraphQL API:
query { withoutName: field # represented as `undefined` in resolvers withNull: field(name: null) withValue: field(name: "string")}
For a nullable input type, adding a defaultValue
will remove the undefined
option but note that it will not remove null
.
const g: GWithContext<unknown>
g.field: <unknown, GScalarType<string, string>, (_: unknown, args: { readonly name: string | null;}) => string | null, { name: GArg<GScalarType<string, string>, true>;}>(field: FieldFuncArgs<...> & { ...;}) => GField<...>
field({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String, args?: { name: GArg<GScalarType<string, string>, true>;}
args: { name: GArg<GScalarType<string, string>, true>
name: const g: GWithContext<unknown>
g.arg: <GScalarType<string, string>, string>(arg: { type: GScalarType<string, string>; description?: Maybe<string>; deprecationReason?: Maybe<string>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String, defaultValue: string
defaultValue: "name" }), }, resolve: ((source: unknown, args: { readonly name: string | null;}, context: unknown, info: GraphQLResolveInfo) => InferValueFromOutputType<GScalarType<string, string>>) & ((_: unknown, args: { ...;}) => string | null)
resolve(_: unknown
_, args) {args: { readonly name: string | null;}
return args: { readonly name: string | null;}
args.name: string | null
name; },});
For non-nullable input types, adding a defaultValue
doesn’t affect the type received by the resolve
function, it just allows the consumer to not provide the argument in which case the default value will be used:
const g: GWithContext<unknown>
g.field: <unknown, GScalarType<string, string>, (_: unknown, args: { readonly name: string;}) => string, { name: GArg<GNonNull<GScalarType<string, string>>, true>;}>(field: FieldFuncArgs<...> & { ...;}) => GField<...>
field({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String, args?: { name: GArg<GNonNull<GScalarType<string, string>>, true>;}
args: { name: GArg<GNonNull<GScalarType<string, string>>, true>
name: const g: GWithContext<unknown>
g.arg: <GNonNull<GScalarType<string, string>>, string>(arg: { type: GNonNull<GScalarType<string, string>>; description?: Maybe<string>; deprecationReason?: Maybe<...>; extensions?: (Readonly<...> & Readonly<...>) | ... 1 more ... | undefined; astNode?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GScalarType<string, string>>
type: const g: GWithContext<unknown>
g.nonNull: <GScalarType<string, string>>(of: GScalarType<string, string>) => GNonNull<GScalarType<string, string>>
nonNull(const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String), defaultValue: string
defaultValue: "name" }), }, resolve: ((source: unknown, args: { readonly name: string;}, context: unknown, info: GraphQLResolveInfo) => InferValueFromOutputType<GScalarType<string, string>>) & ((_: unknown, args: { ...;}) => string)
resolve(_: unknown
_, args) {args: { readonly name: string;}
return args: { readonly name: string;}
args.name: string
name; },});
One Of
To express an input object where a consumer must provide exactly one of the keys, you can use isOneOf
. Note all the fields must be nullable when defining the type but in your resolver, exactly one key will be provided and it will be non-null and no other keys will be provided.
const const UserCreateInput: GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;}, true>
UserCreateInput = const g: GWithContext<unknown>
g.inputObject: <{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;}, true>(config: GInputObjectTypeConfig<...>) => GInputObjectType<...>
inputObject({ name: string
name: "UserSearchInput", isOneOf: true | undefined
isOneOf: true, fields: { id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;} | (() => { id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;})
fields: { id: GArg<GScalarType<string, string>, false>
id: const g: GWithContext<unknown>
g.arg: <GScalarType<string, string>, undefined>(arg: { type: GScalarType<string, string>; description?: Maybe<string>; extensions?: (Readonly<GraphQLInputFieldExtensions> & Readonly<...>) | null | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type ID: GScalarType<string, string>
ID }), email: GArg<GScalarType<string, string>, false>
email: const g: GWithContext<unknown>
g.arg: <GScalarType<string, string>, undefined>(arg: { type: GScalarType<string, string>; description?: Maybe<string>; extensions?: (Readonly<GraphQLInputFieldExtensions> & Readonly<...>) | null | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String }), name: GArg<GScalarType<string, string>, false>
name: const g: GWithContext<unknown>
g.arg: <GScalarType<string, string>, undefined>(arg: { type: GScalarType<string, string>; description?: Maybe<string>; extensions?: (Readonly<GraphQLInputFieldExtensions> & Readonly<...>) | null | undefined; astNode?: Maybe<...>; deprecationReason?: Maybe<...>;} & { ...;}) => GArg<...>
arg({ type: GScalarType<string, string>
type: const g: GWithContext<unknown>
g.type String: GScalarType<string, string>
String }), },});
const const search: GField<unknown, { input: GArg<GNonNull<GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>; }, true>>, false>;}, GObjectType<...>, unknown, unknown>
search = const g: GWithContext<unknown>
g.field: <unknown, GObjectType<UserSource, unknown>, (_: unknown, args: { readonly input: { readonly name: string; readonly id?: never; readonly email?: never; } | { readonly id: string; readonly name?: never; readonly email?: never; } | { ...; };}) => null, { ...;}>(field: FieldFuncArgs<...> & { ...;}) => GField<...>
field({ type: GObjectType<UserSource, unknown>
type: const User: GObjectType<UserSource, unknown>
User, args?: { input: GArg<GNonNull<GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>; }, true>>, false>;}
args: { input: GArg<GNonNull<GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;}, true>>, false>
input: const g: GWithContext<unknown>
g.arg: <GNonNull<GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;}, true>>, undefined>(arg: { ...;} & { ...;}) => GArg<...>
arg({ type: GNonNull<GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;}, true>>
type: const g: GWithContext<unknown>
g.nonNull: <GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;}, true>>(of: GInputObjectType<...>) => GNonNull<...>
nonNull(const UserCreateInput: GInputObjectType<{ id: GArg<GScalarType<string, string>, false>; email: GArg<GScalarType<string, string>, false>; name: GArg<GScalarType<string, string>, false>;}, true>
UserCreateInput) }), }, resolve: ((source: unknown, args: { readonly input: { readonly name: string; readonly id?: never; readonly email?: never; } | { readonly id: string; readonly name?: never; readonly email?: never; } | { readonly email: string; readonly name?: never; readonly id?: never; };}, context: unknown, info: GraphQLResolveInfo) => InferValueFromOutputType<...>) & ((_: unknown, args: { ...;}) => null)
resolve(_: unknown
_, args: { readonly input: { readonly name: string; readonly id?: never; readonly email?: never; } | { readonly id: string; readonly name?: never; readonly email?: never; } | { readonly email: string; readonly name?: never; readonly id?: never; };}
args) { var console: Console
console.Console.log(...data: any[]): void
log(args: { readonly input: { readonly name: string; readonly id?: never; readonly email?: never; } | { readonly id: string; readonly name?: never; readonly email?: never; } | { readonly email: string; readonly name?: never; readonly id?: never; };}
args.input);input: { readonly name: string; readonly id?: never; readonly email?: never;} | { readonly id: string; readonly name?: never; readonly email?: never;} | { readonly email: string; readonly name?: never; readonly id?: never;}
return null; },});