RunTypes relies on TypeScript's type metadata being available at runtime. There are common pitfalls that can prevent this from working correctly. mion provides ESLint rules to catch these issues at development time.
When you use import type { X } or import { type X }, TypeScript completely erases these imports at compile time. This means the type metadata is not available at runtime, and RunTypes cannot generate validation or serialization functions.
// ❌ WRONG: Type-only import - erased at runtime
import type { User } from './types';
route((ctx, id: number): User => getUser(id));
// ✅ CORRECT: Regular import - type metadata preserved
import { User } from './types';
route((ctx, id: number): User => getUser(id));
@mionkit/no-type-imports ESLint rule to catch this issue.RunTypes needs explicit type annotations on route/middleFn parameters and return types. Without them, TypeScript cannot emit the type metadata needed for runtime validation.
// ❌ WRONG: Missing type annotations
route((ctx, user) => user.name);
// ✅ CORRECT: Explicit type annotations
route((ctx, user: User): string => user.name);
@mionkit/strong-typed-routes ESLint rule to catch this issue.typeof with RunType FunctionsUsing typeof with runtime values can lead to incorrect type inference.
The type metadata emitted at compile time is directly attached to type definitions (User type in bellow example).
So using typeof user loses the type metadata.
// ❌ WRONG: typeof infers from current value
const user = { id: '1', name: 'John' };
const userRunType = runType<typeof user>();
// ✅ CORRECT: Explicit type definition
type User = { id: string; name: string };
const userRunType = runType<User>();
@mionkit/no-typeof-runtype ESLint rule to catch this issue.When deserializing union types, RunTypes tries to match against each type in order. If a less specific type appears before a more specific type, the more specific type will never be matched.
// ❌ WRONG: {id: string} matches first, {id: string; name: string} is unreachable
type User = { id: string } | { id: string; name: string };
// ✅ CORRECT: Most specific type first
type User = { id: string; name: string } | { id: string };
@mionkit/no-unreachable-union-types ESLint rule to catch this issue.To catch all these issues automatically, add the mion ESLint plugin to your project:
npm install @mionkit/eslint-plugin -D
Then use the recommended configuration:
{
"extends": ["plugin:@mionkit/recommended"]
}
This enables all the rules mentioned above with error severity.