vite-plugin-convex-types
v1.0.4
Published
A Vite plugin that automatically generates TypeScript types for Convex tables and function return types
Downloads
22
Maintainers
Readme
vite-plugin-convex-types
A Vite plugin that automatically generates more usable TypeScript types for Convex tables and function return types, plus pre-configured React hooks. Don't like accessing your types like Doc<"users"> or dealing with .default syntax? Now you can just do import { User, useGetAllUsersQuery } from "src/types/_generated/convex";.
Releases + Changelogs
https://github.com/AndrewBrough/vite-plugin-convex-types/releases
Features
- ✅ Automatic Type Generation: Creates type exports for all tables in your Convex schema
- ✅ Pre-configured React Hooks: Auto-generated hooks that eliminate the need for
.defaultsyntax - ✅ Function Return Types: Generates return types for queries and mutations
- ✅ Populated Document Types: Creates types for documents with populated relations
- ✅ Hot Reload: Regenerates types when your schema or functions change
- ✅ Singular Naming: Converts plural table names to singular type names (e.g.,
users→User) - ✅ Zero Configuration: Works out of the box with your existing Convex setup
Installation
npm install vite-plugin-convex-typesUsage
1. Add to your Vite config
// vite.config.ts
import { defineConfig } from 'vite';
import { convexTypesPlugin } from 'vite-plugin-convex-types';
export default defineConfig({
plugins: [
convexTypesPlugin({
outputPath: "src/types/_generated/convex.ts",
convexPath: "convex",
importPath: "./convex"
}),
// ... other plugins
],
});2. Import the generated types and hooks
import type {
User,
Article,
UserId,
ArticleId,
ArticleWithAuthor,
GetAllArticlesReturn
} from '../types/_generated/convex';
import {
useGetAllArticlesQuery,
useCreateArticleMutation,
useGetAllUsersQuery
} from '../types/_generated/convex';
// Use them in your components
const ArticleCard = ({ article, onArticleClick }: {
article: ArticleWithAuthor; // Populated article with author object
onArticleClick: (articleId: ArticleId) => void;
}) => {
return (
<div onClick={() => onArticleClick(article._id)}>
<h3>{article.title_md}</h3>
{/* Safely access author properties */}
{article.author && (
<p>By {article.author.name} ({article.author.email})</p>
)}
</div>
);
};
// Use the pre-configured hooks (no more .default syntax!)
const ArticleList = () => {
const articles = useGetAllArticlesQuery({ sort: "desc" });
const createArticle = useCreateArticleMutation();
// Your component logic here...
};Configuration
Options
convexTypesPlugin({
outputPath: 'src/types/_generated/convex.ts', // Where to output types
convexPath: 'convex', // Path to convex directory
importPath: './convex' // Import path prefix for table imports
})Options Reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| outputPath | string | 'src/types/_generated/convex.ts' | Path where generated types will be written |
| convexPath | string | 'convex' | Path to the convex directory |
| importPath | string | './convex' | Import path prefix for table imports in schema |
Generated Types
The plugin automatically generates these types for each table:
Document Types
User- Document type for users tableArticle- Document type for articles table
ID Types
UserId- ID type for users tableArticleId- ID type for articles table
Populated Document Types
ArticleWithAuthor- Article with populated author objectUserWithProfile- User with additional profile fields
Function Return Types
GetAllArticlesReturn- Return type for getAllArticles queryGetCurrentUserReturn- Return type for getCurrentUser queryCreateArticleReturn- Return type for createArticle mutation
Pre-configured React Hooks
useGetAllArticlesQuery(args?)- Hook for getAllArticles queryuseGetAllUsersQuery()- Hook for getAllUsers queryuseGetCurrentUserQuery()- Hook for getCurrentUser queryuseCreateArticleMutation()- Hook for createArticle mutationuseUpdateCurrentUserMutation()- Hook for updateCurrentUser mutation
Advanced Types
import type {
Doc, // Generic document type
Id, // Generic ID type
TableNames, // Union of all table names
GetDocType, // Helper to get doc type for any table
GetIdType, // Helper to get ID type for any table
AllDocTypes, // Mapped type of all document types
AllIdTypes, // Mapped type of all ID types
WithPopulatedField // Generic type for populated fields
} from '../types/_generated/convex';
// Use generic helpers
type CustomUser = GetDocType<"users">;
type CustomUserId = GetIdType<"users">;
// Create custom populated types
type ArticleWithCustomAuthor = WithPopulatedField<Article, 'author', User | null>;How It Works
- Schema Detection: The plugin reads your
convex/schema.tsfile to detect all tables by parsing import statements and table definitions - Import Path Detection: Uses the configured import path (default:
./convex) to find table imports in your schema - Function Analysis: Scans your Convex functions to detect queries and mutations
- Type Generation: Creates type exports using the generated
convex/_generated/dataModel.d.ts - Hook Generation: Auto-generates pre-configured React hooks for all queries and mutations
- Return Type Inference: Analyzes function code to infer return types
- Hot Reload: Watches for changes and regenerates types and hooks automatically
- Output: Writes types and hooks to the specified output path
Requirements
- Node.js: >= 18.0.0
- Vite: >= 4.0.0
- Convex: Any version with TypeScript support
Project Structure
Your project should have this structure:
your-project/
├── convex/
│ ├── schema.ts # Your Convex schema
│ ├── _generated/ # Convex generated files
│ │ └── dataModel.d.ts
│ ├── users/
│ │ └── getCurrentUser.ts # Your Convex functions
│ └── articles/
│ └── getAllArticles.ts
├── src/
│ └── types/
│ └── _generated/ # Plugin output (auto-generated)
│ └── convex.ts
└── vite.config.tsBenefits
- No Manual Maintenance: Types and hooks are always in sync with your schema and functions
- Type Safety: Full TypeScript support with proper field types and return types
- Developer Experience: IntelliSense and autocomplete for all tables, functions, and hooks
- Consistency: Standardized naming across your codebase
- Populated Relations: Proper typing for documents with populated foreign keys
- Simplified API: No more
.defaultsyntax - use pre-configured hooks instead - Auto-regeneration: Hooks are automatically updated when you add new Convex functions
Advanced Configuration
Custom Import Paths
If your Convex schema uses a different import path prefix than the default ./convex, you can configure it (you'd have to have set this up in your own tsconfig.json 'paths')
// vite.config.ts
convexTypesPlugin({
importPath: "@convex" // For imports like: import { users } from "@convex/users"
})This is useful if you have custom path aliases or different import patterns in your schema files.
Troubleshooting
Type Not Generating properly
- Make sure Convex is running:
npm run convex - Check that
convex/_generated/dataModel.d.tsexists before running your app eg.npm run dev - Verify you've configured the plygin is properly structured
Function Return Types Not Detected
- Make sure your functions use
export default query({...})orexport default mutation({...}) - Check that the plugin can find your function files
- Verify the function analysis patterns in the plugin code
Examples
Basic Usage
// Before (manual approach)
import type { Doc, Id } from "./convex/_generated/dataModel";
import { api } from "@convex/_generated/api";
import { useQuery, useMutation } from "convex/react";
type User = Doc<"users">;
type UserId = Id<"users">;
// No return types for functions
const articles = useQuery(api.articles.getAllArticles.default, { sort: "desc" });
const createArticle = useMutation(api.articles.createArticle.default);
// After (with plugin)
import type {
User,
UserId,
GetCurrentUserReturn,
ArticleWithAuthor
} from "../types/_generated/convex";
import {
useGetAllArticlesQuery,
useCreateArticleMutation
} from "../types/_generated/convex";
// Ready to use with full type safety and simplified hooks!
const articles = useGetAllArticlesQuery({ sort: "desc" });
const createArticle = useCreateArticleMutation();With Populated Relations
// Your Convex query returns articles with populated authors
const articles = useGetAllArticlesQuery();
// Use the generated type for type safety
const ArticleList = ({ articles }: { articles: GetAllArticlesReturn }) => {
return (
<div>
{articles.map(article => (
<div key={article._id}>
<h3>{article.title_md}</h3>
{/* TypeScript knows author is populated */}
<p>By {article.author?.name}</p>
</div>
))}
</div>
);
};Using Pre-configured Hooks
// All your Convex functions automatically get pre-configured hooks
const MyComponent = () => {
// Queries
const articles = useGetAllArticlesQuery({ sort: "desc" });
const users = useGetAllUsersQuery();
const currentUser = useGetCurrentUserQuery();
// Mutations
const createArticle = useCreateArticleMutation();
const updateUser = useUpdateCurrentUserMutation();
// All hooks are fully typed with proper arguments and return types
const handleCreateArticle = () => {
createArticle({
title_md: "New Article",
body_md: "Article content"
});
};
return (
// Your component JSX
);
};Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
If you encounter any issues or have questions, please open an issue on GitHub.
