Skip to Content
SchemaEnums

Enum Types

gqlkit converts TypeScript string literal unions and enums to GraphQL enum types.

String Literal Unions

String literal unions are automatically converted to GraphQL enum types:

/** * User account status */ export type UserStatus = "ACTIVE" | "INACTIVE" | "PENDING";

Generates:

"""User account status""" enum UserStatus { ACTIVE INACTIVE PENDING }

TypeScript Enums

TypeScript string enums are also supported:

export enum UserStatus { Active = "ACTIVE", Inactive = "INACTIVE", Pending = "PENDING", }

Generates:

enum UserStatus { ACTIVE INACTIVE PENDING }

Deprecating Enum Values

Use the @deprecated JSDoc tag to mark enum values as deprecated:

export enum UserStatus { Active = "ACTIVE", /** * @deprecated Use `Inactive` instead */ Pending = "PENDING", Inactive = "INACTIVE", }

For string literal unions, use a separate type with JSDoc:

/** * User account status */ export type UserStatus = | "ACTIVE" | /** @deprecated Use INACTIVE instead */ "PENDING" | "INACTIVE";

Generates:

enum UserStatus { ACTIVE PENDING @deprecated(reason: "Use INACTIVE instead") INACTIVE }

Using Enums in Types

export type User = { id: string; name: string; status: UserStatus; }; export type UpdateUserInput = { status: UserStatus | null; };

Generates:

type User { id: String! name: String! status: UserStatus! } input UpdateUserInput { status: UserStatus }

Inline Enums

When you define a string literal union or reference a TypeScript enum inline (without exporting it from the schema directory), gqlkit automatically generates a GraphQL enum type. This follows the same pattern as inline objects.

Inline String Literal Unions

String literal unions used directly in field or argument types generate enum types automatically:

export type User = { id: string; name: string; /** Current account status */ status: "active" | "inactive" | "pendingReview"; };

Generates:

type User { id: String! name: String! """Current account status""" status: UserStatus! } enum UserStatus { ACTIVE INACTIVE PENDING_REVIEW }

The generated enum type name follows the convention {ParentTypeName}{PascalCaseFieldName}.

External TypeScript Enums

TypeScript enums defined outside the schema directory are also automatically converted:

// src/types/order.ts (outside schema directory) /** * Order status in the system */ export enum OrderStatus { /** Order is pending payment */ Pending = "pending", /** Order is being processed */ Processing = "processing", /** Order has been shipped */ Shipped = "shipped", } // src/gqlkit/schema/order.ts import { OrderStatus } from "../../types/order.js"; export type Order = { id: string; status: OrderStatus; };

Generates:

type Order { id: String! status: OrderStatus! } """Order status in the system""" enum OrderStatus { """Order is pending payment""" PENDING """Order is being processed""" PROCESSING """Order has been shipped""" SHIPPED }

TSDoc comments on the enum and its values are preserved as GraphQL descriptions. The @deprecated tag is also supported.

When the same external TypeScript enum is referenced in multiple places, gqlkit generates a single GraphQL enum type and reuses it across all references.

Inline Enum Naming Convention

The naming convention for auto-generated enum types matches inline objects:

ContextNaming PatternExample
Object field{ParentTypeName}{PascalCaseFieldName}User.statusUserStatus
Input field{ParentTypeNameWithoutInputSuffix}{PascalCaseFieldName}InputCreateUserInput.roleCreateUserRoleInput
Query/Mutation argument{PascalCaseFieldName}{PascalCaseArgName}InputsearchUsers(status: ...)SearchUsersStatusInput
Field resolver argument{ParentTypeName}{PascalCaseFieldName}{PascalCaseArgName}InputUser.posts(filter: ...)UserPostsFilterInput

Nullable Inline Enums

Nullable inline enums are supported:

export type User = { id: string; status: "active" | "inactive" | null; };

Generates:

type User { id: String! status: UserStatus } enum UserStatus { ACTIVE INACTIVE }

Arrays of Inline Enums

Inline enums in array types are also supported:

export type User = { id: string; roles: ("admin" | "editor" | "viewer")[]; };

Generates:

type User { id: String! roles: [UserRoles!]! } enum UserRoles { ADMIN EDITOR VIEWER }

When Enums Are NOT Auto-Generated

If you export a type from the schema directory, it is treated as an explicit type declaration and not auto-generated:

// Exported from schema - used as-is, not auto-generated export type UserStatus = "active" | "inactive" | "pending"; export type User = { id: string; status: UserStatus; // References the exported type };

Inline Enum Payloads

String literal unions in resolver return types generate GraphQL Enum types with the naming convention {ResolverName}Payload:

export const getStatus = defineQuery<NoArgs, "active" | "inactive" | "pending">( (_root, _args, ctx) => ctx.db.getStatus() );

Generates:

type Query { getStatus: GetStatusPayload! } enum GetStatusPayload { ACTIVE INACTIVE PENDING }

For field resolvers, the naming convention is {ParentTypeName}{PascalCaseFieldName}Payload:

export const status = defineField<User, NoArgs, "online" | "offline" | "away">( (parent) => parent.currentStatus );

Generates:

type User { status: UserStatusPayload! } enum UserStatusPayload { ONLINE OFFLINE AWAY }

See Queries & Mutations for more details on inline payload types.

Automatic Case Conversion

gqlkit automatically converts enum values to SCREAMING_SNAKE_CASE format, which is the GraphQL convention:

export type UserStatus = "active" | "inProgress" | "pending_review" | "on-hold";

Generates:

enum UserStatus { ACTIVE IN_PROGRESS PENDING_REVIEW ON_HOLD }

When conversion changes the original value, gqlkit generates resolver mappings to translate between GraphQL and TypeScript values:

// Generated resolvers.ts export function createResolvers() { return { UserStatus: { ACTIVE: "active", IN_PROGRESS: "inProgress", PENDING_REVIEW: "pending_review", ON_HOLD: "on-hold", }, }; }

If values are already in SCREAMING_SNAKE_CASE, no resolver mapping is generated.

Automatic Prefix Stripping

When all enum values share a common prefix that matches the enum name, gqlkit automatically strips the prefix to produce cleaner GraphQL values:

export type UserStatus = "USER_STATUS_ACTIVE" | "USER_STATUS_INACTIVE" | "USER_STATUS_PENDING";

Generates:

enum UserStatus { ACTIVE INACTIVE PENDING }

This works with various naming conventions:

TypeScript EnumValuesGenerated GraphQL Values
UserStatusUSER_STATUS_ACTIVE, USER_STATUS_INACTIVEACTIVE, INACTIVE
orderStatusORDER_STATUS_PENDING, ORDER_STATUS_SHIPPEDPENDING, SHIPPED
StatusSTATUS_ACTIVE, STATUS_INACTIVEACTIVE, INACTIVE

Prefix stripping is not applied when:

  • Not all values share the common prefix
  • Stripping would result in an empty value (e.g., USER_STATUS_ for UserStatus)

When prefix stripping is applied, gqlkit generates resolver mappings to preserve the original TypeScript values:

// Generated resolvers.ts export function createResolvers() { return { UserStatus: { ACTIVE: "USER_STATUS_ACTIVE", INACTIVE: "USER_STATUS_INACTIVE", PENDING: "USER_STATUS_PENDING", }, }; }

Duplicate Value Detection

If multiple TypeScript values convert to the same GraphQL enum value, gqlkit reports a DUPLICATE_ENUM_VALUE_AFTER_CONVERSION error:

// Error: 'activeUser' and 'active_user' both convert to ACTIVE_USER export type Status = "activeUser" | "active_user" | "pending";

Invalid Enum Values

Enum values that are not valid GraphQL identifiers are automatically skipped with a warning. gqlkit converts enum values to SCREAMING_SNAKE_CASE, and the converted name must:

  • Match the pattern /^[_A-Za-z][_0-9A-Za-z]*$/
  • Not start with __ (reserved for GraphQL introspection)

String Literal Unions

export type Status = | "active" // ✅ Converts to ACTIVE | "inProgress" // ✅ Converts to IN_PROGRESS | "0pending" // ⚠️ Skipped: converts to 0PENDING (starts with number) | "__internal"; // ⚠️ Skipped: converts to __INTERNAL (starts with __)

Generates:

enum Status { ACTIVE IN_PROGRESS }

TypeScript Enums

export enum Priority { HIGH = "HIGH", // ✅ Valid MEDIUM = "MEDIUM", // ✅ Valid LOW = "LOW", // ✅ Valid "0INVALID" = "0INVALID", // ⚠️ Skipped: starts with number __RESERVED = "__RESERVED", // ⚠️ Skipped: starts with __ }

Generates:

enum Priority { HIGH MEDIUM LOW }

When enum values are skipped, gqlkit outputs a warning with the original name, converted name, and location.

Last updated on