Getting Started
Typelizer is for Rails apps that use a serializer library and a TypeScript-capable frontend (React, Vue, Svelte via Inertia, or a separate SPA). It generates TypeScript interfaces from your serializers and type-safe route helpers from your Rails routes.
If you use jbuilder or render json: model.as_json, you'll need to adopt a serializer library first. If you use server-rendered views (ERB/Haml) without TypeScript, Typelizer's route helpers and OpenAPI schemas may still be useful, but type generation won't apply.
Prerequisites
- Ruby 3.0+
- Rails 6.1+
- A serializer library: Alba, ActiveModel::Serializer, Oj::Serializer, or Panko::Serializer. New to serializers? We recommend Alba.
Installation
Add Typelizer to your Gemfile:
gem "typelizer"Run bundle install.
Set Up Your Serializers
Add Typelizer::DSL to your base serializer class:
class ApplicationResource
include Alba::Resource
helper Typelizer::DSL
endclass ApplicationSerializer < ActiveModel::Serializer
include Typelizer::DSL
endclass ApplicationSerializer < Oj::Serializer
include Typelizer::DSL
endclass ApplicationSerializer < Panko::Serializer
include Typelizer::DSL
endNow define your serializers as usual. Typelizer reads the attributes and infers TypeScript types from your models:
class PostResource < ApplicationResource
attributes :id, :title, :body
has_one :author, serializer: AuthorResource
end
class AuthorResource < ApplicationResource
# Specify the model to infer types from (optional)
typelize_from User
attributes :id, :name
endGenerate TypeScript Types
Run the generator:
rails typelizer:generateTypelizer creates TypeScript interfaces in app/javascript/types/serializers/:
// app/javascript/types/serializers/Post.ts
export interface Post {
id: number;
title: string;
body: string;
author: Author;
}All interfaces are re-exported from a barrel file:
// app/javascript/types/serializers/index.ts
export * from "./Post";
export * from "./Author";Use in Your TypeScript Code
Import the generated types:
import { Post } from "@/types";
function renderPost(post: Post) {
console.log(post.title);
}We recommend creating a central app/javascript/types/index.ts that re-exports the generated types:
// app/javascript/types/index.ts
export * from "./serializers";
// Add your custom types hereThe "@/types" import path is configurable via types_import_path.
Auto-Regeneration in Development
When the Listen gem is installed, Typelizer automatically watches your serializer files and regenerates interfaces on change. Disable this if needed:
Typelizer.listen = falseTo clean the output directory and regenerate everything:
rails typelizer:generate:refreshTo disable Typelizer entirely in development (without affecting manual generation), set the environment variable:
TYPELIZER=falseRoute Helpers
Without route helpers, you hardcode URL strings -- typos are silent and params aren't checked:
fetch(`/users/${userId}/posts`) // hope the URL is rightTypelizer generates type-safe route functions from your config/routes.rb. Enable it in an initializer:
# config/initializers/typelizer.rb
Typelizer.configure do |config|
config.routes.enabled = true
endRun rails typelizer:generate, then use the generated helpers:
import { posts } from "@/routes";
posts.index() // => { url: "/posts", method: "get" }
posts.show(42) // => { url: "/posts/42", method: "get" }
posts.show() // TypeScript error: missing required paramAutocompletion, compile-time checking, no string URLs. See the Route Helpers guide for the full walkthrough.
Next Steps
- Manual Typing -- annotate computed attributes with custom types
- Serializer guides: Alba, AMS, Oj, Panko
- Route Helpers -- type-safe route functions from Rails routes
- Multiple Writers -- emit different outputs (e.g., snake_case and camelCase)
- Configuration Reference -- all available options