Skip to content

refactor: from manual type definitions to GraphQL codegen#42

Closed
iamfj wants to merge 31 commits intoczottmann:mainfrom
iamfj:type-generator
Closed

refactor: from manual type definitions to GraphQL codegen#42
iamfj wants to merge 31 commits intoczottmann:mainfrom
iamfj:type-generator

Conversation

@iamfj
Copy link
Collaborator

@iamfj iamfj commented Feb 2, 2026

Replaces manual TypeScript type definitions with automatically generated types from the Linear GraphQL schema using @graphql-codegen. This migration eliminates ~330 lines of manually maintained type definitions and ensures our types stay in sync with the actual Linear API.

Motivation

The Problem:

  • Manual type definitions (linear-types.d.ts) required constant maintenance as the Linear API evolved
  • No compile-time guarantee that our manual types matched the actual GraphQL schema
  • Type drift could silently introduce bugs when Linear updated their API
  • Developers had to manually inspect GraphQL responses and write corresponding TypeScript interfaces

The Solution:
GraphQL Code Generator automatically creates TypeScript types directly from:

  1. The Linear GraphQL schema (source of truth)
  2. Our actual GraphQL queries and mutations (what we use in practice)

This means our types are always accurate and reflect exactly what the API returns for our specific queries.

Changes

Type System Migration

  • Deleted: src/utils/linear-types.d.ts (330 lines of manual types)
  • Added: Automatic type generation via @graphql-codegen/client-preset
  • Migrated Services:
    • graphql-issues-service.ts - Added type aliases, removed transformation layer
    • graphql-documents-service.ts - Migrated to codegen types
    • graphql-attachments-service.ts - Migrated to codegen types
    • linear-service.ts - Added type aliases for custom return shapes

Command Layer Updates

  • issues.ts - Fixed parameter types to match codegen
  • cycles.ts - Added missing option interfaces, use codegen types
  • project-milestones.ts - Added option interfaces, use codegen types

Architecture Improvements

  • Services now return raw codegen types directly (no transformation layer)
  • Union types handle different query return shapes (e.g., IssueFromId | IssueFromIdentifier)
  • Type aliases improve readability while maintaining full type safety

Benefits

1. Type Safety

  • Compile-time errors if we access fields that don't exist in the actual schema
  • Automatic type narrowing based on actual GraphQL responses
  • No more "trust me, this field exists" assertions

2. Maintainability

  • Schema changes automatically reflected in our types (run `npm run generate`)
  • No manual type updates needed when Linear updates their API
  • Reduced risk of type drift causing runtime errors

3. Developer Experience

  • IntelliSense/autocomplete based on actual schema fields
  • Immediate feedback when using deprecated or removed fields
  • Clear documentation of what data each query returns

4. Code Quality

  • Removed 330 lines of manual type definitions
  • Eliminated custom transformation layer (was mapping between manual types and SDK types)
  • Simplified service methods - return raw types instead of transforming

JSON output should be identical to previous behavior.

Breaking Changes

None. This is a refactoring that maintains the same external API and JSON output structure.

Dependencies

Added:

  • @graphql-codegen/cli - Code generation tooling
  • @graphql-codegen/client-preset - TypeScript type generation
  • @graphql-codegen/introspection - Schema introspection
  • @graphql-codegen/schema-ast - Schema AST utilities

Future Improvements

  • Fix prestart script (should be npm run generate not generate)
  • Consider adding GraphQL schema validation to CI
  • Add generated types to .gitignore if we want to generate on-demand

@iamfj iamfj changed the title feat: add GraphQL codegen for schema-derived types [WIP] feat: add GraphQL codegen for schema-derived types Feb 2, 2026
iamfj and others added 21 commits February 3, 2026 00:48
Add type aliases for GraphQL query/mutation return types to improve
readability in method signatures.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return raw codegen types directly instead of transforming to manual
types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return union type of raw codegen types instead of transforming.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return raw codegen type directly.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Return raw codegen type directly.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Use QuerySearchIssuesArgs instead of full query type. Remove
transformation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Delete transformIssueData and doTransformIssueData - no longer needed
since services return raw codegen types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Pass QuerySearchIssuesArgs fields directly instead of wrong type.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Ensure parameters match IssueUpdateInput type from codegen.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add type aliases, remove transformations, return raw GraphQL types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add type aliases, remove transformations, return raw GraphQL types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Define CycleListOptions and CycleReadOptions locally. Replace
LinearCycle with codegen type alias.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add missing option interfaces (MilestoneListOptions, MilestoneReadOptions,
MilestoneCreateOptions, MilestoneUpdateOptions) and replace
LinearProjectMilestone with ProjectMilestoneUpdateInput from codegen.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change the identifier used in the error message when an issue is not found during resolution from `id` to `resolvedIssueId` for improved clarity and accuracy.
Delete linear-types.d.ts - all types now generated from GraphQL
schema via codegen.

- Add type aliases in linear-service.ts for LinearLabel, LinearComment,
  and CreateCommentArgs
- Replace LinearProject with inline type definition
- Fix bug in graphql-issues-service.ts: use input.projectMilestoneId
  instead of input.milestoneId
- Remove dead code for milestone fallback lookup

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@iamfj iamfj changed the title [WIP] feat: add GraphQL codegen for schema-derived types refactor: migrate from manual type definitions to GraphQL codegen Feb 2, 2026
@iamfj iamfj changed the title refactor: migrate from manual type definitions to GraphQL codegen refactor: from manual type definitions to GraphQL codegen Feb 2, 2026
iamfj added 5 commits February 3, 2026 10:34
Updated the GraphQL requests in the GraphQLIssuesService to enforce return types using codegen types. Added comments to clarify the importance of matching the return type with the appropriate GraphQL document.
Reformatted import statements for better readability and consistency. Aligned async calls for GraphQL requests to enhance code clarity. This change does not affect functionality but improves maintainability.
iamfj added 5 commits February 3, 2026 10:44
Updated the FileService class to utilize the generated FileUploadDocument for the GraphQL file upload mutation, enhancing type safety and maintainability. Removed the hardcoded mutation string in favor of the imported document.
@iamfj
Copy link
Collaborator Author

iamfj commented Feb 4, 2026

I started this work to introduce strict typing across the API. This alone fixed a few minor bugs and made the codebase feel much more robust.

As I dug deeper, I noticed some overly complex architectures that I’d like to simplify. Since that’s out of scope here, I’ve started a v2 branch in my fork to address those issues and other requests from the community.

My goal isn’t to create a competing CLI, but to build a clean, robust, and well-tested version that can be reintegrated into the original project. I appreciate the work @czottmann has done and have already reached out.

I’ll keep you posted and will open a draft PR for v2 soon.

Best,

@iamfj

@iamfj iamfj closed this Feb 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant